routing_test.rb 73.3 KB
Newer Older
1
# encoding: utf-8
2 3
require 'abstract_unit'
require 'controller/fake_controllers'
4
require 'active_support/dependencies'
5

J
Jeremy Kemper 已提交
6 7 8 9 10 11
class MilestonesController < ActionController::Base
  def index() head :ok end
  alias_method :show, :index
  def rescue_action(e) raise e end
end

12
ROUTING = ActionController::Routing
13

14 15
class ROUTING::RouteBuilder
  attr_reader :warn_output
16

17 18
  def warn(msg)
    (@warn_output ||= []) << msg
19
  end
20
end
21

22
# See RFC 3986, section 3.3 for allowed path characters.
23 24 25 26 27
class UriReservedCharactersRoutingTest < Test::Unit::TestCase
  def setup
    ActionController::Routing.use_controllers! ['controller']
    @set = ActionController::Routing::RouteSet.new
    @set.draw do |map|
28
      map.connect ':controller/:action/:variable/*additional'
29
    end
30

31
    safe, unsafe = %w(: @ & = + $ , ;), %w(^ / ? # [ ])
32 33
    hex = unsafe.map { |char| '%' + char.unpack('H2').first.upcase }

34 35
    @segment = "#{safe.join}#{unsafe.join}".freeze
    @escaped = "#{safe.join}#{hex.join}".freeze
36
  end
37 38

  def test_route_generation_escapes_unsafe_path_characters
39
    assert_equal "/contr#{@segment}oller/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2",
40 41
      @set.generate(:controller => "contr#{@segment}oller",
                    :action => "act#{@segment}ion",
42 43
                    :variable => "var#{@segment}iable",
                    :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"])
44
  end
45 46

  def test_route_recognition_unescapes_path_components
47
    options = { :controller => "content",
48
                :action => "act#{@segment}ion",
49 50
                :variable => "var#{@segment}iable",
                :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"] }
51
    assert_equal options, @set.recognize_path("/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2")
52
  end
53 54 55 56 57 58 59

  def test_route_generation_allows_passing_non_string_values_to_generated_helper
    assert_equal "/controller/action/variable/1/2", @set.generate(:controller => "controller",
                                                                  :action => "action",
                                                                  :variable => "variable",
                                                                  :additional => [1, 2])
  end
60 61
end

62 63 64 65 66 67
class RoutingTest < Test::Unit::TestCase
  def test_normalize_unix_paths
    load_paths = %w(. config/../app/controllers config/../app//helpers script/../config/../vendor/rails/actionpack/lib vendor/rails/railties/builtin/rails_info app/models lib script/../config/../foo/bar/../../app/models .foo/../.bar foo.bar/../config)
    paths = ActionController::Routing.normalize_paths(load_paths)
    assert_equal %w(vendor/rails/railties/builtin/rails_info vendor/rails/actionpack/lib app/controllers app/helpers app/models config .bar lib .), paths
  end
68

69 70 71 72
  def test_normalize_windows_paths
    load_paths = %w(. config\\..\\app\\controllers config\\..\\app\\\\helpers script\\..\\config\\..\\vendor\\rails\\actionpack\\lib vendor\\rails\\railties\\builtin\\rails_info app\\models lib script\\..\\config\\..\\foo\\bar\\..\\..\\app\\models .foo\\..\\.bar foo.bar\\..\\config)
    paths = ActionController::Routing.normalize_paths(load_paths)
    assert_equal %w(vendor\\rails\\railties\\builtin\\rails_info vendor\\rails\\actionpack\\lib app\\controllers app\\helpers app\\models config .bar lib .), paths
73 74
  end

75 76
  def test_routing_helper_module
    assert_kind_of Module, ActionController::Routing::Helpers
77

78 79 80 81 82
    h = ActionController::Routing::Helpers
    c = Class.new
    assert ! c.ancestors.include?(h)
    ActionController::Routing::Routes.install_helpers c
    assert c.ancestors.include?(h)
83
  end
84
end
85

86 87
class MockController
  attr_accessor :routes
88

89 90 91
  def initialize(routes)
    self.routes = routes
  end
92

93 94
  def url_for(options)
    only_path = options.delete(:only_path)
95

96 97
    port        = options.delete(:port) || 80
    port_string = port == 80 ? '' : ":#{port}"
98

99 100 101
    protocol = options.delete(:protocol) || "http"
    host     = options.delete(:host) || "test.host"
    anchor   = "##{options.delete(:anchor)}" if options.key?(:anchor)
102

103
    path = routes.generate(options)
104

105 106
    only_path ? "#{path}#{anchor}" : "#{protocol}://#{host}#{port_string}#{path}#{anchor}"
  end
107

108 109
  def request
    @request ||= ActionController::TestRequest.new
110
  end
111
end
112

113 114
class LegacyRouteSetTests < Test::Unit::TestCase
  attr_reader :rs
115

116 117 118 119 120 121 122 123
  def setup
    # These tests assume optimisation is on, so re-enable it.
    ActionController::Base.optimise_named_routes = true

    @rs = ::ActionController::Routing::RouteSet.new

    ActionController::Routing.use_controllers! %w(content admin/user admin/news_feed)
  end
J
Joshua Peek 已提交
124

125 126 127 128 129 130 131 132 133 134 135 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
  def teardown
    @rs.clear!
  end

  def test_default_setup
    @rs.draw {|m| m.connect ':controller/:action/:id' }
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
    assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list"))
    assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10"))

    assert_equal({:controller => "admin/user", :action => 'show', :id => '10'}, rs.recognize_path("/admin/user/show/10"))

    assert_equal '/admin/user/show/10', rs.generate(:controller => 'admin/user', :action => 'show', :id => 10)

    assert_equal '/admin/user/show', rs.generate({:action => 'show'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
    assert_equal '/admin/user/list/10', rs.generate({}, {:controller => 'admin/user', :action => 'list', :id => '10'})

    assert_equal '/admin/stuff', rs.generate({:controller => 'stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
    assert_equal '/stuff', rs.generate({:controller => '/stuff'}, {:controller => 'admin/user', :action => 'list', :id => '10'})
  end

  def test_ignores_leading_slash
    @rs.clear!
    @rs.draw {|m| m.connect '/:controller/:action/:id'}
    test_default_setup
  end

  def test_time_recognition
    # We create many routes to make situation more realistic
    @rs = ::ActionController::Routing::RouteSet.new
    @rs.draw { |map|
      map.frontpage '', :controller => 'search', :action => 'new'
      map.resources :videos do |video|
        video.resources :comments
        video.resource  :file,      :controller => 'video_file'
        video.resource  :share,     :controller => 'video_shares'
        video.resource  :abuse,     :controller => 'video_abuses'
      end
      map.resources :abuses, :controller => 'video_abuses'
      map.resources :video_uploads
      map.resources :video_visits

      map.resources :users do |user|
        user.resource  :settings
        user.resources :videos
      end
      map.resources :channels do |channel|
        channel.resources :videos, :controller => 'channel_videos'
      end
      map.resource  :session
      map.resource  :lost_password
      map.search    'search', :controller => 'search'
      map.resources :pages
      map.connect ':controller/:action/:id'
    }
  end
181

182 183 184 185
  def test_route_with_colon_first
    rs.draw do |map|
      map.connect '/:controller/:action/:id', :action => 'index', :id => nil
      map.connect ':url', :controller => 'tiny_url', :action => 'translate'
186
    end
187 188 189 190 191 192
  end

  def test_route_with_regexp_for_controller
    rs.draw do |map|
      map.connect ':controller/:admintoken/:action/:id', :controller => /admin\/.+/
      map.connect ':controller/:action/:id'
193
    end
194 195 196 197 198 199
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
    assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo"))
    assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index")
    assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo")
  end
200

201 202 203 204 205 206
  def test_route_with_regexp_and_captures_for_controller
    rs.draw do |map|
      map.connect ':controller/:action/:id', :controller => /admin\/(accounts|users)/
    end
    assert_equal({:controller => "admin/accounts", :action => "index"}, rs.recognize_path("/admin/accounts"))
    assert_equal({:controller => "admin/users", :action => "index"}, rs.recognize_path("/admin/users"))
207
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
208 209
  end

210 211 212 213 214 215 216 217 218 219 220 221 222 223
  def test_route_with_regexp_and_dot
    rs.draw do |map|
      map.connect ':controller/:action/:file',
                        :controller => /admin|user/,
                        :action => /upload|download/,
                        :defaults => {:file => nil},
                        :requirements => {:file => %r{[^/]+(\.[^/]+)?}}
    end
    # Without a file extension
    assert_equal '/user/download/file',
      rs.generate(:controller => "user", :action => "download", :file => "file")
    assert_equal(
      {:controller => "user", :action => "download", :file => "file"},
      rs.recognize_path("/user/download/file"))
224

225 226 227 228 229 230 231 232
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
      rs.generate(
        :controller => "user", :action => "download", :file => "file.jpg")
    assert_equal(
      {:controller => "user", :action => "download", :file => "file.jpg"},
      rs.recognize_path("/user/download/file.jpg"))
  end
233

234 235 236 237 238 239
  def test_basic_named_route
    rs.add_named_route :home, '', :controller => 'content', :action => 'list'
    x = setup_for_named_route
    assert_equal("http://test.host/",
                 x.send(:home_url))
  end
240

241 242 243 244 245 246 247 248 249
  def test_basic_named_route_with_relative_url_root
    rs.add_named_route :home, '', :controller => 'content', :action => 'list'
    x = setup_for_named_route
    ActionController::Base.relative_url_root = "/foo"
    assert_equal("http://test.host/foo/",
                 x.send(:home_url))
    assert_equal "/foo/", x.send(:home_path)
    ActionController::Base.relative_url_root = nil
  end
250

251 252 253 254 255 256
  def test_named_route_with_option
    rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page'
    x = setup_for_named_route
    assert_equal("http://test.host/page/new%20stuff",
                 x.send(:page_url, :title => 'new stuff'))
  end
257

258 259 260 261 262
  def test_named_route_with_default
    rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
    x = setup_for_named_route
    assert_equal("http://test.host/page/AboutRails",
                 x.send(:page_url, :title => "AboutRails"))
263

264
  end
265

266 267 268 269 270 271
  def test_named_route_with_name_prefix
    rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :name_prefix => 'my_'
    x = setup_for_named_route
    assert_equal("http://test.host/page",
                 x.send(:my_page_url))
  end
J
Joshua Peek 已提交
272

273 274 275 276 277 278
  def test_named_route_with_path_prefix
    rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :path_prefix => 'my'
    x = setup_for_named_route
    assert_equal("http://test.host/my/page",
                 x.send(:page_url))
  end
279

280 281 282 283 284 285 286
  def test_named_route_with_blank_path_prefix
    rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :path_prefix => ''
    x = setup_for_named_route
    assert_equal("http://test.host/page",
                 x.send(:page_url))
  end

287 288 289 290 291 292
  def test_named_route_with_nested_controller
    rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
    x = setup_for_named_route
    assert_equal("http://test.host/admin/user",
                 x.send(:users_url))
  end
293

294 295 296 297 298 299 300 301 302 303
  def test_optimised_named_route_call_never_uses_url_for
    rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index'
    rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
    x = setup_for_named_route
    x.expects(:url_for).never
    x.send(:users_url)
    x.send(:users_path)
    x.send(:user_url, 2, :foo=>"bar")
    x.send(:user_path, 3, :bar=>"foo")
  end
304

305 306 307 308 309 310
  def test_optimised_named_route_with_host
    rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
    x = setup_for_named_route
    x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
    x.send(:pages_url)
  end
311

312 313 314 315 316
  def setup_for_named_route
    klass = Class.new(MockController)
    rs.install_helpers(klass)
    klass.new(rs)
  end
317

318 319 320
  def test_named_route_without_hash
    rs.draw do |map|
      map.normal ':controller/:action/:id'
321
    end
322
  end
323

324 325 326
  def test_named_route_root
    rs.draw do |map|
      map.root :controller => "hello"
327
    end
328 329 330 331
    x = setup_for_named_route
    assert_equal("http://test.host/", x.send(:root_url))
    assert_equal("/", x.send(:root_path))
  end
332

333 334 335 336 337
  def test_named_route_with_regexps
    rs.draw do |map|
      map.article 'page/:year/:month/:day/:title', :controller => 'page', :action => 'show',
        :year => /\d+/, :month => /\d+/, :day => /\d+/
      map.connect ':controller/:action/:id'
338
    end
339 340 341 342 343 344 345 346 347 348
    x = setup_for_named_route
    # assert_equal(
    #   {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false},
    #   x.send(:article_url, :title => 'hi')
    # )
    assert_equal(
      "http://test.host/page/2005/6/10/hi",
      x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
    )
  end
349

350 351
  def test_changing_controller
    @rs.draw {|m| m.connect ':controller/:action/:id' }
352

353 354 355 356 357
    assert_equal '/admin/stuff/show/10', rs.generate(
      {:controller => 'stuff', :action => 'show', :id => 10},
      {:controller => 'admin/user', :action => 'index'}
    )
  end
358

359 360 361 362
  def test_paths_escaped
    rs.draw do |map|
      map.path 'file/*path', :controller => 'content', :action => 'show_file'
      map.connect ':controller/:action/:id'
363
    end
364

365 366 367 368
    # No + to space in URI escaping, only for query params.
    results = rs.recognize_path "/file/hello+world/how+are+you%3F"
    assert results, "Recognition should have succeeded"
    assert_equal ['hello+world', 'how+are+you?'], results[:path]
369

370 371 372 373
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
    assert_equal ['hello world', 'how are you?'], results[:path]
374

375 376 377 378
    results = rs.recognize_path "/file"
    assert results, "Recognition should have succeeded"
    assert_equal [], results[:path]
  end
379

380 381
  def test_paths_slashes_unescaped_with_ordered_parameters
    rs.add_named_route :path, '/file/*path', :controller => 'content'
382

383 384 385 386
    # No / to %2F in URI, only for query params.
    x = setup_for_named_route
    assert_equal("/file/hello/world", x.send(:path_path, 'hello/world'))
  end
387

388 389 390
  def test_non_controllers_cannot_be_matched
    rs.draw do |map|
      map.connect ':controller/:action/:id'
391
    end
392
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
393
  end
394

395
  def test_paths_do_not_accept_defaults
396
    assert_raise(ActionController::RoutingError) do
397
      rs.draw do |map|
398 399
        map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => %w(fake default)
        map.connect ':controller/:action/:id'
400 401 402
      end
    end

403 404 405
    rs.draw do |map|
      map.path 'file/*path', :controller => 'content', :action => 'show_file', :path => []
      map.connect ':controller/:action/:id'
406
    end
407
  end
408

409 410 411
  def test_should_list_options_diff_when_routing_requirements_dont_match
    rs.draw do |map|
      map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
412
    end
413 414 415 416 417 418
    exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
    assert_match /^post_url failed to generate/, exception.message
    from_match = exception.message.match(/from \{[^\}]+\}/).to_s
    assert_match /:bad_param=>"foo"/,   from_match
    assert_match /:action=>"show"/,     from_match
    assert_match /:controller=>"post"/, from_match
419

420 421 422 423
    expected_match = exception.message.match(/expected: \{[^\}]+\}/).to_s
    assert_no_match /:bad_param=>"foo"/,   expected_match
    assert_match    /:action=>"show"/,     expected_match
    assert_match    /:controller=>"post"/, expected_match
424

425 426 427 428 429 430 431 432 433 434
    diff_match = exception.message.match(/diff: \{[^\}]+\}/).to_s
    assert_match    /:bad_param=>"foo"/,   diff_match
    assert_no_match /:action=>"show"/,     diff_match
    assert_no_match /:controller=>"post"/, diff_match
  end

  # this specifies the case where your formerly would get a very confusing error message with an empty diff
  def test_should_have_better_error_message_when_options_diff_is_empty
    rs.draw do |map|
      map.content '/content/:query', :controller => 'content', :action => 'show'
435 436
    end

437 438 439 440 441 442
    exception = assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'content', :action => 'show', :use_route => "content") }
    assert_match %r[:action=>"show"], exception.message
    assert_match %r[:controller=>"content"], exception.message
    assert_match %r[you may have ambiguous routes, or you may need to supply additional parameters for this route], exception.message
    assert_match %r[content_url has the following required parameters: \["content", :query\] - are they all satisfied?], exception.message
  end
443

444 445 446 447
  def test_dynamic_path_allowed
    rs.draw do |map|
      map.connect '*path', :controller => 'content', :action => 'show_file'
    end
448

449 450
    assert_equal '/pages/boo', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo))
  end
451

452 453 454
  def test_dynamic_recall_paths_allowed
    rs.draw do |map|
      map.connect '*path', :controller => 'content', :action => 'show_file'
455 456
    end

457
    assert_equal '/pages/boo', rs.generate({}, :controller => 'content', :action => 'show_file', :path => %w(pages boo))
458
  end
459

460 461 462 463
  def test_backwards
    rs.draw do |map|
      map.connect 'page/:id/:action', :controller => 'pages', :action => 'show'
      map.connect ':controller/:action/:id'
464 465
    end

466 467 468 469 470 471 472 473 474
    assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'})
    assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show')
    assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo')
  end

  def test_route_with_fixnum_default
    rs.draw do |map|
      map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
      map.connect ':controller/:action/:id'
475 476
    end

477 478 479 480
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page')
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1)
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1')
    assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10)
481

482 483 484 485 486 487 488 489 490 491
    assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page"))
    assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1"))
    assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10"))
  end

  # For newer revision
  def test_route_with_text_default
    rs.draw do |map|
      map.connect 'page/:id', :controller => 'content', :action => 'show_page', :id => 1
      map.connect ':controller/:action/:id'
492 493
    end

494 495
    assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo')
    assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
496

497 498
    token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
    escaped_token = CGI::escape(token)
499

500 501 502
    assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
    assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}"))
  end
503

504 505 506 507
  def test_action_expiry
    @rs.draw {|m| m.connect ':controller/:action/:id' }
    assert_equal '/content', rs.generate({:controller => 'content'}, {:controller => 'content', :action => 'show'})
  end
508

509 510 511 512 513 514 515 516 517 518
  def test_recognition_with_uppercase_controller_name
    @rs.draw {|m| m.connect ':controller/:action/:id' }
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/Content"))
    assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/ConTent/list"))
    assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/CONTENT/show/10"))

    # these used to work, before the routes rewrite, but support for this was pulled in the new version...
    #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/NewsFeed"))
    #assert_equal({'controller' => "admin/news_feed", 'action' => 'index'}, rs.recognize_path("Admin/News_Feed"))
  end
519

520 521 522
  def test_requirement_should_prevent_optional_id
    rs.draw do |map|
      map.post 'post/:id', :controller=> 'post', :action=> 'show', :requirements => {:id => /\d+/}
523 524
    end

525
    assert_equal '/post/10', rs.generate(:controller => 'post', :action => 'show', :id => 10)
526

527
    assert_raise ActionController::RoutingError do
528
      rs.generate(:controller => 'post', :action => 'show')
529
    end
530
  end
531

532 533 534 535 536 537 538 539
  def test_both_requirement_and_optional
    rs.draw do |map|
      map.blog('test/:year', :controller => 'post', :action => 'show',
        :defaults => { :year => nil },
        :requirements => { :year => /\d{4}/ }
      )
      map.connect ':controller/:action/:id'
    end
540

541 542 543 544 545 546 547
    assert_equal '/test', rs.generate(:controller => 'post', :action => 'show')
    assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil)

    x = setup_for_named_route
    assert_equal("http://test.host/test",
                 x.send(:blog_url))
  end
548

549 550 551 552
  def test_set_to_nil_forgets
    rs.draw do |map|
      map.connect 'pages/:year/:month/:day', :controller => 'content', :action => 'list_pages', :month => nil, :day => nil
      map.connect ':controller/:action/:id'
553 554
    end

555 556 557 558 559 560
    assert_equal '/pages/2005',
      rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005)
    assert_equal '/pages/2005/6',
      rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6)
    assert_equal '/pages/2005/6/12',
      rs.generate(:controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12)
561

562 563
    assert_equal '/pages/2005/6/4',
      rs.generate({:day => 4}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
564

565 566
    assert_equal '/pages/2005/6',
      rs.generate({:day => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
567

568 569 570
    assert_equal '/pages/2005',
      rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
  end
571

572 573 574 575
  def test_url_with_no_action_specified
    rs.draw do |map|
      map.connect '', :controller => 'content'
      map.connect ':controller/:action/:id'
576 577
    end

578 579 580
    assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
    assert_equal '/', rs.generate(:controller => 'content')
  end
581

582 583 584 585
  def test_named_url_with_no_action_specified
    rs.draw do |map|
      map.home '', :controller => 'content'
      map.connect ':controller/:action/:id'
586 587
    end

588 589
    assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
    assert_equal '/', rs.generate(:controller => 'content')
590

591 592 593 594
    x = setup_for_named_route
    assert_equal("http://test.host/",
                 x.send(:home_url))
  end
595

596 597
  def test_url_generated_when_forgetting_action
    [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash|
598
      rs.draw do |map|
599
        map.home '', hash
600 601
        map.connect ':controller/:action/:id'
      end
602 603 604 605 606
      assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
      assert_equal '/', rs.generate({:controller => 'content'})
      assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
    end
  end
607

608 609 610 611
  def test_named_route_method
    rs.draw do |map|
      map.categories 'categories', :controller => 'content', :action => 'categories'
      map.connect ':controller/:action/:id'
612 613
    end

614 615 616 617 618 619 620 621
    assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories')
    assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
  end

  def test_named_routes_array
    test_named_route_method
    assert_equal [:categories], rs.named_routes.names
  end
622

623 624 625 626 627 628 629 630
  def test_nil_defaults
    rs.draw do |map|
      map.connect 'journal',
        :controller => 'content',
        :action => 'list_journal',
        :date => nil, :user_id => nil
      map.connect ':controller/:action/:id'
    end
631

632 633
    assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil)
  end
634

635 636 637 638
  def setup_request_method_routes_for(method)
    @request = ActionController::TestRequest.new
    @request.env["REQUEST_METHOD"] = method
    @request.request_uri = "/match"
639

640 641 642 643 644
    rs.draw do |r|
      r.connect '/match', :controller => 'books', :action => 'get', :conditions => { :method => :get }
      r.connect '/match', :controller => 'books', :action => 'post', :conditions => { :method => :post }
      r.connect '/match', :controller => 'books', :action => 'put', :conditions => { :method => :put }
      r.connect '/match', :controller => 'books', :action => 'delete', :conditions => { :method => :delete }
645
    end
646
  end
647

648 649 650 651 652 653 654 655 656 657 658
  %w(GET POST PUT DELETE).each do |request_method|
    define_method("test_request_method_recognized_with_#{request_method}") do
      begin
        Object.const_set(:BooksController, Class.new(ActionController::Base))

        setup_request_method_routes_for(request_method)

        assert_nothing_raised { rs.recognize(@request) }
        assert_equal request_method.downcase, @request.path_parameters[:action]
      ensure
        Object.send(:remove_const, :BooksController) rescue nil
659
      end
660 661
    end
  end
662

663 664 665 666 667
  def test_recognize_array_of_methods
    Object.const_set(:BooksController, Class.new(ActionController::Base))
    rs.draw do |r|
      r.connect '/match', :controller => 'books', :action => 'get_or_post', :conditions => { :method => [:get, :post] }
      r.connect '/match', :controller => 'books', :action => 'not_get_or_post'
668 669
    end

670 671 672 673 674
    @request = ActionController::TestRequest.new
    @request.env["REQUEST_METHOD"] = 'POST'
    @request.request_uri = "/match"
    assert_nothing_raised { rs.recognize(@request) }
    assert_equal 'get_or_post', @request.path_parameters[:action]
675

676 677 678 679 680 681 682 683 684
    # have to recreate or else the RouteSet uses a cached version:
    @request = ActionController::TestRequest.new
    @request.env["REQUEST_METHOD"] = 'PUT'
    @request.request_uri = "/match"
    assert_nothing_raised { rs.recognize(@request) }
    assert_equal 'not_get_or_post', @request.path_parameters[:action]
  ensure
    Object.send(:remove_const, :BooksController) rescue nil
  end
685

686 687
  def test_subpath_recognized
    Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))
688

689 690 691 692 693
    rs.draw do |r|
      r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
      r.connect '/items/:id/:action', :controller => 'subpath_books'
      r.connect '/posts/new/:action', :controller => 'subpath_books'
      r.connect '/posts/:id', :controller => 'subpath_books', :action => "show"
694 695
    end

696 697 698
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
699

700 701 702 703 704 705 706 707 708 709 710 711 712 713
    hash = rs.recognize_path "/items/3/complete"
    assert_not_nil hash
    assert_equal %w(subpath_books 3 complete), [hash[:controller], hash[:id], hash[:action]]

    hash = rs.recognize_path "/posts/new/preview"
    assert_not_nil hash
    assert_equal %w(subpath_books preview), [hash[:controller], hash[:action]]

    hash = rs.recognize_path "/posts/7"
    assert_not_nil hash
    assert_equal %w(subpath_books show 7), [hash[:controller], hash[:action], hash[:id]]
  ensure
    Object.send(:remove_const, :SubpathBooksController) rescue nil
  end
714

715 716 717 718 719 720 721
  def test_subpath_generated
    Object.const_set(:SubpathBooksController, Class.new(ActionController::Base))

    rs.draw do |r|
      r.connect '/books/:id/edit', :controller => 'subpath_books', :action => 'edit'
      r.connect '/items/:id/:action', :controller => 'subpath_books'
      r.connect '/posts/new/:action', :controller => 'subpath_books'
722 723
    end

724 725 726 727 728 729
    assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
    assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
    assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
  ensure
    Object.send(:remove_const, :SubpathBooksController) rescue nil
  end
730

731 732 733
  def test_failed_requirements_raises_exception_with_violated_requirements
    rs.draw do |r|
      r.foo_with_requirement 'foos/:id', :controller=>'foos', :requirements=>{:id=>/\d+/}
734 735
    end

736
    x = setup_for_named_route
737
    assert_raise(ActionController::RoutingError) do
738 739 740
      x.send(:foo_with_requirement_url, "I am Against the requirements")
    end
  end
741

742 743 744 745 746 747 748 749 750
  def test_routes_changed_correctly_after_clear
    ActionController::Base.optimise_named_routes = true
    rs = ::ActionController::Routing::RouteSet.new
    rs.draw do |r|
      r.connect 'ca', :controller => 'ca', :action => "aa"
      r.connect 'cb', :controller => 'cb', :action => "ab"
      r.connect 'cc', :controller => 'cc', :action => "ac"
      r.connect ':controller/:action/:id'
      r.connect ':controller/:action/:id.:format'
751 752
    end

753
    hash = rs.recognize_path "/cc"
754

755 756
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
757

758 759 760 761 762
    rs.draw do |r|
      r.connect 'cb', :controller => 'cb', :action => "ab"
      r.connect 'cc', :controller => 'cc', :action => "ac"
      r.connect ':controller/:action/:id'
      r.connect ':controller/:action/:id.:format'
763 764
    end

765
    hash = rs.recognize_path "/cc"
766

767 768
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
769

770 771
  end
end
772

773
class RouteSetTest < ActiveSupport::TestCase
774 775 776
  def set
    @set ||= ROUTING::RouteSet.new
  end
777

778 779 780
  def request
    @request ||= ActionController::TestRequest.new
  end
781

782 783 784 785 786 787 788 789 790 791 792 793 794
  def default_route_set
    @default_route_set ||= begin
      set = nil
      ActionController::Routing.with_controllers(['accounts']) do
        set = ROUTING::RouteSet.new
        set.draw do |map|
          map.connect '/:controller/:action/:id/'
        end
      end
      set
    end
  end

795 796 797 798
  def test_generate_extras
    set.draw { |m| m.connect ':controller/:action/:id' }
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
799
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
800
  end
801

802 803 804
  def test_extra_keys
    set.draw { |m| m.connect ':controller/:action/:id' }
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
805
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
806
  end
807

808 809 810 811
  def test_generate_extras_not_first
    set.draw do |map|
      map.connect ':controller/:action/:id.:format'
      map.connect ':controller/:action/:id'
812
    end
813 814
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
815
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
816
  end
817

818 819 820 821
  def test_generate_not_first
    set.draw do |map|
      map.connect ':controller/:action/:id.:format'
      map.connect ':controller/:action/:id'
822
    end
823 824
    assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello")
  end
825

826 827 828 829
  def test_extra_keys_not_first
    set.draw do |map|
      map.connect ':controller/:action/:id.:format'
      map.connect ':controller/:action/:id'
830
    end
831
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
832
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
833
  end
834

835 836 837 838
  def test_draw
    assert_equal 0, set.routes.size
    set.draw do |map|
      map.connect '/hello/world', :controller => 'a', :action => 'b'
839
    end
840 841
    assert_equal 1, set.routes.size
  end
842

843 844 845 846 847 848 849 850 851 852 853
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
    set.draw do |map|
      map.connect '/users/index', :controller => :users, :action => :index
    end
    @request = ActionController::TestRequest.new
    @request.request_uri = '/users/index'
    assert_nothing_raised { set.recognize(@request) }
    assert_equal 1, set.routes.size
  end

854 855 856 857
  def test_named_draw
    assert_equal 0, set.routes.size
    set.draw do |map|
      map.hello '/hello/world', :controller => 'a', :action => 'b'
858
    end
859 860 861
    assert_equal 1, set.routes.size
    assert_equal set.routes.first, set.named_routes[:hello]
  end
862

863 864 865 866
  def test_later_named_routes_take_precedence
    set.draw do |map|
      map.hello '/hello/world', :controller => 'a', :action => 'b'
      map.hello '/hello', :controller => 'a', :action => 'b'
867
    end
868 869
    assert_equal set.routes.last, set.named_routes[:hello]
  end
870

871 872 873 874 875 876
  def setup_named_route_test
    set.draw do |map|
      map.show '/people/:id', :controller => 'people', :action => 'show'
      map.index '/people', :controller => 'people', :action => 'index'
      map.multi '/people/go/:foo/:bar/joe/:id', :controller => 'people', :action => 'multi'
      map.users '/admin/users', :controller => 'admin/users', :action => 'index'
877 878
    end

879 880 881 882
    klass = Class.new(MockController)
    set.install_helpers(klass)
    klass.new(set)
  end
883

884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
  def test_named_route_hash_access_method
    controller = setup_named_route_test

    assert_equal(
      { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => false },
      controller.send(:hash_for_show_url, :id => 5))

    assert_equal(
      { :controller => 'people', :action => 'index', :use_route => :index, :only_path => false },
      controller.send(:hash_for_index_url))

    assert_equal(
      { :controller => 'people', :action => 'show', :id => 5, :use_route => :show, :only_path => true },
      controller.send(:hash_for_show_path, :id => 5)
    )
899 900
  end

901 902
  def test_named_route_url_method
    controller = setup_named_route_test
903

904 905
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
906

907 908
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
909

910 911 912 913
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
    assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'})
  end
914

915 916
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
917

918 919
    assert_equal "http://test.host/people/5#location", controller.send(:show_url, :id => 5, :anchor => 'location')
    assert_equal "/people/5#location", controller.send(:show_path, :id => 5, :anchor => 'location')
920

921 922
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
923

924 925
    assert_equal "http://test.host/admin/users#location", controller.send(:users_url, :anchor => 'location')
    assert_equal '/admin/users#location', controller.send(:users_path, :anchor => 'location')
926

927 928
    assert_equal "http://test.host/people/go/7/hello/joe/5#location",
      controller.send(:multi_url, 7, "hello", 5, :anchor => 'location')
929

930 931
    assert_equal "http://test.host/people/go/7/hello/joe/5?baz=bar#location",
      controller.send(:multi_url, 7, "hello", 5, :baz => "bar", :anchor => 'location')
932

933 934 935
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
936

937 938 939 940
  def test_named_route_url_method_with_port
    controller = setup_named_route_test
    assert_equal "http://test.host:8080/people/5", controller.send(:show_url, 5, :port=>8080)
  end
941

942 943 944 945
  def test_named_route_url_method_with_host
    controller = setup_named_route_test
    assert_equal "http://some.example.com/people/5", controller.send(:show_url, 5, :host=>"some.example.com")
  end
946

947 948 949 950
  def test_named_route_url_method_with_protocol
    controller = setup_named_route_test
    assert_equal "https://test.host/people/5", controller.send(:show_url, 5, :protocol => "https")
  end
951

952 953 954 955 956
  def test_named_route_url_method_with_ordered_parameters
    controller = setup_named_route_test
    assert_equal "http://test.host/people/go/7/hello/joe/5",
      controller.send(:multi_url, 7, "hello", 5)
  end
957

958 959 960 961 962
  def test_named_route_url_method_with_ordered_parameters_and_hash
    controller = setup_named_route_test
    assert_equal "http://test.host/people/go/7/hello/joe/5?baz=bar",
      controller.send(:multi_url, 7, "hello", 5, :baz => "bar")
  end
963

964 965 966 967 968
  def test_named_route_url_method_with_ordered_parameters_and_empty_hash
    controller = setup_named_route_test
    assert_equal "http://test.host/people/go/7/hello/joe/5",
      controller.send(:multi_url, 7, "hello", 5, {})
  end
969

970 971 972 973 974
  def test_named_route_url_method_with_no_positional_arguments
    controller = setup_named_route_test
    assert_equal "http://test.host/people?baz=bar",
      controller.send(:index_url, :baz => "bar")
  end
975

976 977 978 979 980
  def test_draw_default_route
    ActionController::Routing.with_controllers(['users']) do
      set.draw do |map|
        map.connect '/:controller/:action/:id'
      end
981

982 983
      assert_equal 1, set.routes.size
      route = set.routes.first
984

985
      assert route.segments.last.optional?
986

987 988
      assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
      assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
989

990 991
      assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10'))
      assert_equal({:controller => 'users', :action => 'index', :id => '10'}, set.recognize_path('/users/index/10/'))
992
    end
993
  end
994

995 996 997 998
  def test_draw_default_route_with_default_controller
    ActionController::Routing.with_controllers(['users']) do
      set.draw do |map|
        map.connect '/:controller/:action/:id', :controller => 'users'
999
      end
1000
      assert_equal({:controller => 'users', :action => 'index'}, set.recognize_path('/'))
1001
    end
1002
  end
1003

1004 1005 1006 1007 1008
  def test_route_with_parameter_shell
    ActionController::Routing.with_controllers(['users', 'pages']) do
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/
        map.connect '/:controller/:action/:id'
1009 1010
      end

1011 1012 1013
      assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages'))
      assert_equal({:controller => 'pages', :action => 'index'}, set.recognize_path('/pages/index'))
      assert_equal({:controller => 'pages', :action => 'list'}, set.recognize_path('/pages/list'))
1014

1015 1016
      assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/pages/show/10'))
      assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
1017
    end
1018
  end
1019

1020
  def test_route_requirements_with_anchor_chars_are_invalid
1021
    assert_raise ArgumentError do
1022 1023
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /^\d+/
1024
      end
1025
    end
1026
    assert_raise ArgumentError do
1027 1028
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\A\d+/
1029 1030
      end
    end
1031
    assert_raise ArgumentError do
1032 1033
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+$/
1034 1035
      end
    end
1036
    assert_raise ArgumentError do
1037 1038
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\Z/
1039 1040
      end
    end
1041
    assert_raise ArgumentError do
1042
      set.draw do |map|
1043
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+\z/
1044
      end
1045 1046 1047 1048
    end
    assert_nothing_raised do
      set.draw do |map|
        map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /\d+/, :name => /^(david|jamis)/
1049
      end
1050
      assert_raise ActionController::RoutingError do
1051
        set.generate :controller => 'pages', :action => 'show', :id => 10
1052 1053
      end
    end
1054
  end
1055

1056
  def test_route_requirements_with_invalid_http_method_is_invalid
1057
    assert_raise ArgumentError do
1058
      set.draw do |map|
1059
        map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :invalid}
1060 1061
      end
    end
1062
  end
1063

1064 1065 1066 1067 1068 1069 1070 1071
  def test_route_requirements_with_options_method_condition_is_valid
    assert_nothing_raised do
      set.draw do |map|
        map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :options}
      end
    end
  end

1072
  def test_route_requirements_with_head_method_condition_is_invalid
1073
    assert_raise ArgumentError do
1074
      set.draw do |map|
1075
        map.connect 'valid/route', :controller => 'pages', :action => 'show', :conditions => {:method => :head}
1076
      end
1077 1078
    end
  end
1079

1080 1081 1082 1083 1084
  def test_non_path_route_requirements_match_all
    set.draw do |map|
      map.connect 'page/37s', :controller => 'pages', :action => 'show', :name => /(jamis|david)/
    end
    assert_equal '/page/37s', set.generate(:controller => 'pages', :action => 'show', :name => 'jamis')
1085
    assert_raise ActionController::RoutingError do
1086 1087
      set.generate(:controller => 'pages', :action => 'show', :name => 'not_jamis')
    end
1088
    assert_raise ActionController::RoutingError do
1089 1090 1091
      set.generate(:controller => 'pages', :action => 'show', :name => 'nor_jamis_and_david')
    end
  end
1092

1093 1094 1095 1096
  def test_recognize_with_encoded_id_and_regex
    set.draw do |map|
      map.connect 'page/:id', :controller => 'pages', :action => 'show', :id => /[a-zA-Z0-9\+]+/
    end
1097

1098 1099 1100 1101 1102 1103
    assert_equal({:controller => 'pages', :action => 'show', :id => '10'}, set.recognize_path('/page/10'))
    assert_equal({:controller => 'pages', :action => 'show', :id => 'hello+world'}, set.recognize_path('/page/hello+world'))
  end

  def test_recognize_with_conditions
    Object.const_set(:PeopleController, Class.new)
1104

1105 1106 1107 1108 1109 1110 1111 1112
    set.draw do |map|
      map.with_options(:controller => "people") do |people|
        people.people  "/people",     :action => "index",   :conditions => { :method => :get }
        people.connect "/people",     :action => "create",  :conditions => { :method => :post }
        people.person  "/people/:id", :action => "show",    :conditions => { :method => :get }
        people.connect "/people/:id", :action => "update",  :conditions => { :method => :put }
        people.connect "/people/:id", :action => "destroy", :conditions => { :method => :delete }
      end
1113 1114
    end

1115
    request.request_uri = "/people"
1116 1117 1118 1119
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("index", request.path_parameters[:action])
    request.recycle!
1120

1121 1122 1123 1124
    request.env["REQUEST_METHOD"] = "POST"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("create", request.path_parameters[:action])
    request.recycle!
1125

1126 1127 1128 1129
    request.env["REQUEST_METHOD"] = "PUT"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("update", request.path_parameters[:action])
    request.recycle!
1130

1131
    assert_raise(ActionController::UnknownHttpMethod) {
1132 1133 1134 1135
      request.env["REQUEST_METHOD"] = "BACON"
      set.recognize(request)
    }
    request.recycle!
1136

1137
    request.request_uri = "/people/5"
1138 1139 1140 1141 1142
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("show", request.path_parameters[:action])
    assert_equal("5", request.path_parameters[:id])
    request.recycle!
1143

1144 1145 1146 1147 1148
    request.env["REQUEST_METHOD"] = "PUT"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("update", request.path_parameters[:action])
    assert_equal("5", request.path_parameters[:id])
    request.recycle!
1149

1150 1151 1152 1153 1154
    request.env["REQUEST_METHOD"] = "DELETE"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("destroy", request.path_parameters[:action])
    assert_equal("5", request.path_parameters[:id])
    request.recycle!
1155

1156 1157 1158 1159 1160 1161
    begin
      request.env["REQUEST_METHOD"] = "POST"
      set.recognize(request)
      flunk 'Should have raised MethodNotAllowed'
    rescue ActionController::MethodNotAllowed => e
      assert_equal [:get, :put, :delete], e.allowed_methods
1162
    end
1163
    request.recycle!
1164

1165 1166 1167
  ensure
    Object.send(:remove_const, :PeopleController)
  end
1168

1169 1170
  def test_recognize_with_alias_in_conditions
    Object.const_set(:PeopleController, Class.new)
1171

1172 1173 1174 1175
    set.draw do |map|
      map.people "/people", :controller => 'people', :action => "index",
        :conditions => { :method => :get }
      map.root   :people
1176
    end
1177

1178 1179 1180 1181 1182
    request.path = "/people"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("people", request.path_parameters[:controller])
    assert_equal("index", request.path_parameters[:action])
1183

1184 1185 1186 1187 1188 1189 1190 1191
    request.path = "/"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("people", request.path_parameters[:controller])
    assert_equal("index", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :PeopleController)
  end
1192

1193 1194
  def test_typo_recognition
    Object.const_set(:ArticlesController, Class.new)
1195

1196 1197 1198 1199
    set.draw do |map|
      map.connect 'articles/:year/:month/:day/:title',
             :controller => 'articles', :action => 'permalink',
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
1200
    end
1201

1202 1203 1204 1205 1206 1207 1208 1209
    request.path = "/articles/2005/11/05/a-very-interesting-article"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("permalink", request.path_parameters[:action])
    assert_equal("2005", request.path_parameters[:year])
    assert_equal("11", request.path_parameters[:month])
    assert_equal("05", request.path_parameters[:day])
    assert_equal("a-very-interesting-article", request.path_parameters[:title])
1210

1211 1212 1213
  ensure
    Object.send(:remove_const, :ArticlesController)
  end
1214

1215 1216 1217 1218
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
    set.draw do |map|
      map.connect '/profile', :controller => 'profile'
1219 1220
    end

1221
    request.path = '/profile'
1222

1223
    set.recognize(request) rescue nil
1224

1225 1226 1227 1228 1229
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
    Object.const_set(:PeopleController, Class.new)
1230

1231 1232 1233 1234 1235
    set.draw do |map|
      map.with_options(:controller => "people") do |people|
        people.person  "/people/:id", :action => "show",    :conditions => { :method => :get }
        people.connect "/people/:id", :action => "update",  :conditions => { :method => :put }
        people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get }
1236
      end
1237 1238
    end

1239
    request.request_uri = "/people/5"
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("show", request.path_parameters[:action])
    assert_equal("5", request.path_parameters[:id])
    request.recycle!

    request.env["REQUEST_METHOD"] = "PUT"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("update", request.path_parameters[:action])
    request.recycle!
1250

1251
    request.request_uri = "/people/5.png"
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("show", request.path_parameters[:action])
    assert_equal("5", request.path_parameters[:id])
    assert_equal("png", request.path_parameters[:_format])
  ensure
    Object.send(:remove_const, :PeopleController)
  end

  def test_generate_with_default_action
    set.draw do |map|
      map.connect "/people", :controller => "people"
      map.connect "/people/list", :controller => "people", :action => "list"
1265 1266
    end

1267 1268 1269
    url = set.generate(:controller => "people", :action => "list")
    assert_equal "/people/list", url
  end
1270

1271 1272
  def test_root_map
    Object.const_set(:PeopleController, Class.new)
1273

1274
    set.draw { |map| map.root :controller => "people" }
1275

1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
    request.path = ""
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("people", request.path_parameters[:controller])
    assert_equal("index", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :PeopleController)
  end

  def test_namespace
    Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })

    set.draw do |map|

      map.namespace 'api' do |api|
        api.route 'inventory', :controller => "products", :action => 'inventory'
1292
      end
1293

1294 1295
    end

1296 1297 1298 1299 1300 1301 1302 1303
    request.path = "/api/inventory"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("api/products", request.path_parameters[:controller])
    assert_equal("inventory", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :Api)
  end
1304

1305 1306
  def test_namespaced_root_map
    Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
1307

1308
    set.draw do |map|
1309

1310 1311
      map.namespace 'api' do |api|
        api.root :controller => "products"
1312 1313 1314 1315
      end

    end

1316 1317 1318 1319 1320 1321 1322 1323
    request.path = "/api"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("api/products", request.path_parameters[:controller])
    assert_equal("index", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :Api)
  end
1324

1325 1326
  def test_namespace_with_path_prefix
    Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })
1327

1328 1329 1330
    set.draw do |map|
      map.namespace 'api', :path_prefix => 'prefix' do |api|
        api.route 'inventory', :controller => "products", :action => 'inventory'
1331
      end
1332 1333
    end

1334 1335 1336 1337 1338 1339 1340 1341
    request.path = "/prefix/inventory"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("api/products", request.path_parameters[:controller])
    assert_equal("inventory", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :Api)
  end
1342

1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360
  def test_namespace_with_blank_path_prefix
    Object.const_set(:Api, Module.new { |m| m.const_set(:ProductsController, Class.new) })

    set.draw do |map|
      map.namespace 'api', :path_prefix => '' do |api|
        api.route 'inventory', :controller => "products", :action => 'inventory'
      end
    end

    request.path = "/inventory"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("api/products", request.path_parameters[:controller])
    assert_equal("inventory", request.path_parameters[:action])
  ensure
    Object.send(:remove_const, :Api)
  end

1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
  def test_generate_changes_controller_module
    set.draw { |map| map.connect ':controller/:action/:id' }
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
    url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current)
    assert_equal "/foo/bar/baz/7", url
  end

  def test_id_is_not_impossibly_sticky
    set.draw do |map|
      map.connect 'foo/:number', :controller => "people", :action => "index"
      map.connect ':controller/:action/:id'
1372 1373
    end

1374 1375 1376 1377
    url = set.generate({:controller => "people", :action => "index", :number => 3},
      {:controller => "people", :action => "index", :id => "21"})
    assert_equal "/foo/3", url
  end
1378

1379 1380 1381
  def test_id_is_sticky_when_it_ought_to_be
    set.draw do |map|
      map.connect ':controller/:id/:action'
1382
    end
1383

1384 1385 1386
    url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
    assert_equal "/people/7/destroy", url
  end
1387

1388 1389 1390 1391
  def test_use_static_path_when_possible
    set.draw do |map|
      map.connect 'about', :controller => "welcome", :action => "about"
      map.connect ':controller/:action/:id'
1392 1393
    end

1394 1395 1396 1397
    url = set.generate({:controller => "welcome", :action => "about"},
      {:controller => "welcome", :action => "get", :id => "7"})
    assert_equal "/about", url
  end
1398

1399 1400
  def test_generate
    set.draw { |map| map.connect ':controller/:action/:id' }
1401

1402 1403 1404 1405 1406
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
    assert_equal "/foo/bar/7?x=y", set.generate(args)
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1407

1408 1409
  def test_generate_with_path_prefix
    set.draw { |map| map.connect ':controller/:action/:id', :path_prefix => 'my' }
1410

1411 1412 1413 1414
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
    assert_equal "/my/foo/bar/7?x=y", set.generate(args)
  end

1415 1416 1417 1418 1419 1420 1421
  def test_generate_with_blank_path_prefix
    set.draw { |map| map.connect ':controller/:action/:id', :path_prefix => '' }

    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
    assert_equal "/foo/bar/7?x=y", set.generate(args)
  end

1422 1423 1424 1425 1426
  def test_named_routes_are_never_relative_to_modules
    set.draw do |map|
      map.connect "/connection/manage/:action", :controller => 'connection/manage'
      map.connect "/connection/connection", :controller => "connection/connection"
      map.family_connection "/connection", :controller => "connection"
1427
    end
1428

1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
    url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
    assert_equal "/connection/connection", url

    url = set.generate({:use_route => :family_connection, :controller => "connection"}, {:controller => 'connection/manage'})
    assert_equal "/connection", url
  end

  def test_action_left_off_when_id_is_recalled
    set.draw do |map|
      map.connect ':controller/:action/:id'
1439
    end
1440 1441 1442 1443 1444
    assert_equal '/post', set.generate(
      {:controller => 'post', :action => 'index'},
      {:controller => 'post', :action => 'show', :id => '10'}
    )
  end
1445

1446 1447 1448 1449
  def test_query_params_will_be_shown_when_recalled
    set.draw do |map|
      map.connect 'show_post/:parameter', :controller => 'post', :action => 'show'
      map.connect ':controller/:action/:id'
1450
    end
1451 1452 1453 1454 1455
    assert_equal '/post/edit?parameter=1', set.generate(
      {:action => 'edit', :parameter => 1},
      {:controller => 'post', :action => 'show', :parameter => 1}
    )
  end
1456

1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
  def test_format_is_not_inherit
    set.draw do |map|
      map.connect '/posts.:format', :controller => 'posts'
    end

    assert_equal '/posts', set.generate(
      {:controller => 'posts'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )

    assert_equal '/posts.xml', set.generate(
      {:controller => 'posts', :format => 'xml'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )
  end

1473 1474 1475 1476 1477 1478
  def test_expiry_determination_should_consider_values_with_to_param
    set.draw { |map| map.connect 'projects/:project_id/:controller/:action' }
    assert_equal '/projects/1/post/show', set.generate(
      {:action => 'show', :project_id => 1},
      {:controller => 'post', :action => 'show', :project_id => '1'})
  end
1479

1480 1481 1482 1483
  def test_generate_all
    set.draw do |map|
      map.connect 'show_post/:id', :controller => 'post', :action => 'show'
      map.connect ':controller/:action/:id'
1484
    end
1485 1486 1487 1488 1489 1490 1491 1492
    all = set.generate(
      {:action => 'show', :id => 10, :generate_all => true},
      {:controller => 'post', :action => 'show'}
    )
    assert_equal 2, all.length
    assert_equal '/show_post/10', all.first
    assert_equal '/post/show/10', all.last
  end
1493

1494 1495 1496 1497
  def test_named_route_in_nested_resource
    set.draw do |map|
      map.resources :projects do |project|
        project.milestones 'milestones', :controller => 'milestones', :action => 'index'
1498 1499
      end
    end
1500

1501 1502 1503 1504 1505 1506
    request.path = "/projects/1/milestones"
    request.env["REQUEST_METHOD"] = "GET"
    assert_nothing_raised { set.recognize(request) }
    assert_equal("milestones", request.path_parameters[:controller])
    assert_equal("index", request.path_parameters[:action])
  end
1507

1508 1509 1510 1511 1512
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
      set.draw do |map|
        map.namespace :admin do |admin|
          admin.root :controller => 'home'
1513 1514 1515
        end
      end
    end
1516
  end
1517

1518 1519 1520 1521 1522
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
      set.draw do |map|
        map.namespace 'admin' do |admin|
          admin.root :controller => 'home'
1523 1524 1525
        end
      end
    end
1526
  end
1527

1528
  def test_route_requirements_with_unsupported_regexp_options_must_error
1529
    assert_raise ArgumentError do
1530 1531 1532
      set.draw do |map|
        map.connect 'page/:name', :controller => 'pages',
          :action => 'show',
1533
          :requirements => {:name => /(david|jamis)/m}
1534
      end
1535
    end
1536
  end
1537

1538 1539
  def test_route_requirements_with_supported_options_must_not_error
    assert_nothing_raised do
1540 1541 1542 1543 1544 1545
      set.draw do |map|
        map.connect 'page/:name', :controller => 'pages',
          :action => 'show',
          :requirements => {:name => /(david|jamis)/i}
      end
    end
1546
    assert_nothing_raised do
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
      set.draw do |map|
        map.connect 'page/:name', :controller => 'pages',
          :action => 'show',
          :requirements => {:name => / # Desperately overcommented regexp
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
                                      )/x}
      end
    end
1558
  end
1559

1560 1561 1562 1563 1564 1565 1566
  def test_route_requirement_recognize_with_ignore_case
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => /(david|jamis)/i}
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1567
    assert_raise ActionController::RoutingError do
1568
      set.recognize_path('/page/davidjamis')
1569
    end
1570 1571
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1572

1573 1574 1575 1576 1577 1578 1579 1580
  def test_route_requirement_generate_with_ignore_case
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => /(david|jamis)/i}
    end
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
    assert_equal "/page/david", url
1581
    assert_raise ActionController::RoutingError do
1582
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
J
Jeremy Kemper 已提交
1583
    end
1584 1585 1586
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
    assert_equal "/page/JAMIS", url
  end
J
Jeremy Kemper 已提交
1587

1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
  def test_route_requirement_recognize_with_extended_syntax
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => / # Desperately overcommented regexp
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/x}
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
    assert_equal({:controller => 'pages', :action => 'show', :name => 'david'}, set.recognize_path('/page/david'))
1601
    assert_raise ActionController::RoutingError do
1602 1603
      set.recognize_path('/page/david #The Creator')
    end
1604
    assert_raise ActionController::RoutingError do
1605
      set.recognize_path('/page/David')
1606 1607
    end
  end
1608

1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
  def test_route_requirement_generate_with_extended_syntax
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => / # Desperately overcommented regexp
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/x}
    end
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
    assert_equal "/page/david", url
1622
    assert_raise ActionController::RoutingError do
1623 1624
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
    end
1625
    assert_raise ActionController::RoutingError do
1626 1627 1628
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
    end
  end
1629

1630 1631 1632 1633 1634 1635 1636 1637 1638 1639
  def test_route_requirement_generate_with_xi_modifiers
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => / # Desperately overcommented regexp
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1640
    end
1641 1642 1643
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
    assert_equal "/page/JAMIS", url
  end
1644

1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
  def test_route_requirement_recognize_with_xi_modifiers
    set.draw do |map|
      map.connect 'page/:name', :controller => 'pages',
        :action => 'show',
        :requirements => {:name => / # Desperately overcommented regexp
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1655
    end
1656 1657
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS'))
  end
1658 1659 1660 1661 1662 1663 1664 1665 1666 1667

  def test_routes_with_symbols
    set.draw do |map|
      map.connect 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol
      map.named   'named',   :controller => :pages, :action => :show, :name => :as_symbol
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/unnamed'))
    assert_equal({:controller => 'pages', :action => 'show', :name => :as_symbol}, set.recognize_path('/named'))
  end

1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765

  def test_interpolation_chunk_should_respect_raw
    ActionController::Routing.with_controllers(['hello']) do
      set.draw do |map|
        map.connect '/Hello World', :controller => 'hello'
      end

      assert_equal '/Hello%20World', set.generate(:controller => 'hello')
      assert_equal({:controller => "hello", :action => "index"}, set.recognize_path('/Hello World'))
      assert_raise(ActionController::RoutingError) { set.recognize_path('/Hello%20World') }
    end
  end

  def test_value_should_not_be_double_unescaped
    ActionController::Routing.with_controllers(['foo']) do
      set.draw do |map|
        map.connect '/Карта', :controller => 'foo'
      end

      assert_equal '/%D0%9A%D0%B0%D1%80%D1%82%D0%B0', set.generate(:controller => 'foo')
      assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/Карта'))
      assert_raise(ActionController::RoutingError) { set.recognize_path('/%D0%9A%D0%B0%D1%80%D1%82%D0%B0') }
    end
  end

  def test_regexp_chunk_should_escape_specials
    ActionController::Routing.with_controllers(['foo', 'bar']) do
      set.draw do |map|
        map.connect '/Hello*World', :controller => 'foo'
        map.connect '/HelloWorld', :controller => 'bar'
      end

      assert_equal '/Hello*World', set.generate(:controller => 'foo')
      assert_equal '/HelloWorld', set.generate(:controller => 'bar')

      assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/Hello*World'))
      assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/HelloWorld'))
    end
  end

  def test_regexp_chunk_should_add_question_mark_for_optionals
    ActionController::Routing.with_controllers(['foo', 'bar']) do
      set.draw do |map|
        map.connect '/', :controller => 'foo'
        map.connect '/hello', :controller => 'bar'
      end

      assert_equal '/', set.generate(:controller => 'foo')
      assert_equal '/hello', set.generate(:controller => 'bar')

      assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/'))
      assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello'))
    end
  end

  def test_assign_route_options_with_anchor_chars
    ActionController::Routing.with_controllers(['cars']) do
      set.draw do |map|
        map.connect '/cars/:action/:person/:car/', :controller => 'cars'
      end

      assert_equal '/cars/buy/1/2', set.generate(:controller => 'cars', :action => 'buy', :person => '1', :car => '2')

      assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2'))
    end
  end

  def test_segmentation_of_dot_path
    ActionController::Routing.with_controllers(['books']) do
      set.draw do |map|
        map.connect '/books/:action.rss', :controller => 'books'
      end

      assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list')

      assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss'))
    end
  end

  def test_segmentation_of_dynamic_dot_path
    ActionController::Routing.with_controllers(['books']) do
      set.draw do |map|
        map.connect '/books/:action.:format', :controller => 'books'
      end

      assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list', :format => 'rss')
      assert_equal '/books/list.xml', set.generate(:controller => 'books', :action => 'list', :format => 'xml')
      assert_equal '/books/list', set.generate(:controller => 'books', :action => 'list')
      assert_equal '/books', set.generate(:controller => 'books', :action => 'index')

      assert_equal({:controller => "books", :action => "list", :format => "rss"}, set.recognize_path('/books/list.rss'))
      assert_equal({:controller => "books", :action => "list", :format => "xml"}, set.recognize_path('/books/list.xml'))
      assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list'))
      assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
    end
  end

  def test_slashes_are_implied
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779
    ['/:controller/:action/:id/', '/:controller/:action/:id',
      ':controller/:action/:id', '/:controller/:action/:id/'
    ].each do |path|
      @set = nil
      set.draw { |map| map.connect(path) }

      assert_equal '/content', set.generate(:controller => 'content', :action => 'index')
      assert_equal '/content/list', set.generate(:controller => 'content', :action => 'list')
      assert_equal '/content/show/1', set.generate(:controller => 'content', :action => 'show', :id => '1')

      assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content'))
      assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index'))
      assert_equal({:controller => "content", :action => "list"}, set.recognize_path('/content/list'))
      assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1'))
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 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872
    end
  end

  def test_default_route_recognition
    expected = {:controller => 'accounts', :action => 'show', :id => '10'}
    assert_equal expected, default_route_set.recognize_path('/accounts/show/10')
    assert_equal expected, default_route_set.recognize_path('/accounts/show/10/')

    expected[:id] = 'jamis'
    assert_equal expected, default_route_set.recognize_path('/accounts/show/jamis/')

    expected.delete :id
    assert_equal expected, default_route_set.recognize_path('/accounts/show')
    assert_equal expected, default_route_set.recognize_path('/accounts/show/')

    expected[:action] = 'index'
    assert_equal expected, default_route_set.recognize_path('/accounts/')
    assert_equal expected, default_route_set.recognize_path('/accounts')

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/accounts/how/goood/it/is/to/be/free') }
  end

  def test_default_route_should_omit_default_action
    assert_equal '/accounts', default_route_set.generate({:controller => 'accounts', :action => 'index'})
  end

  def test_default_route_should_include_default_action_when_id_present
    assert_equal '/accounts/index/20', default_route_set.generate({:controller => 'accounts', :action => 'index', :id => '20'})
  end

  def test_default_route_should_work_with_action_but_no_id
    assert_equal '/accounts/list_all', default_route_set.generate({:controller => 'accounts', :action => 'list_all'})
  end

  def test_default_route_should_uri_escape_pluses
    expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' }
    assert_equal expected, default_route_set.recognize_path('/accounts/show/hello world')
    assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%20world')
    assert_equal '/accounts/show/hello%20world', default_route_set.generate(expected, expected)

    expected[:id] = 'hello+world'
    assert_equal expected, default_route_set.recognize_path('/accounts/show/hello+world')
    assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%2Bworld')
    assert_equal '/accounts/show/hello+world', default_route_set.generate(expected, expected)
  end

  def test_parameter_shell
    page_url = ROUTING::Route.new
    page_url.requirements = {:controller => 'pages', :action => 'show', :id => /\d+/}
    assert_equal({:controller => 'pages', :action => 'show'}, page_url.parameter_shell)
  end

  def test_defaults
    route = ROUTING::RouteBuilder.new.build '/users/:id.:format', :controller => "users", :action => "show", :format => "html"
    assert_equal(
      { :controller => "users", :action => "show", :format => "html" },
      route.defaults)
  end

  def test_builder_complains_without_controller
    assert_raise(ArgumentError) do
      ROUTING::RouteBuilder.new.build '/contact', :contoller => "contact", :action => "index"
    end
  end

  def test_build_empty_query_string
    assert_equal '/foo', default_route_set.generate({:controller => 'foo'})
  end

  def test_build_query_string_with_nil_value
    assert_equal '/foo', default_route_set.generate({:controller => 'foo', :x => nil})
  end

  def test_simple_build_query_string
    assert_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => '1', :y => '2'})
  end

  def test_convert_ints_build_query_string
    assert_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => 1, :y => 2})
  end

  def test_escape_spaces_build_query_string
    assert_equal '/foo?x=hello+world&y=goodbye+world', default_route_set.generate({:controller => 'foo', :x => 'hello world', :y => 'goodbye world'})
  end

  def test_expand_array_build_query_string
    assert_equal '/foo?x%5B%5D=1&x%5B%5D=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]})
  end

  def test_escape_spaces_build_query_string_selected_keys
    assert_equal '/foo?x=hello+world', default_route_set.generate({:controller => 'foo', :x => 'hello world'})
  end
1873
end
1874

1875 1876 1877
class RouteLoadingTest < Test::Unit::TestCase
  def setup
    routes.instance_variable_set '@routes_last_modified', nil
1878 1879
    Object.remove_const(:RAILS_ROOT) if defined?(::RAILS_ROOT)
    Object.const_set :RAILS_ROOT, '.'
1880
    routes.add_configuration_file(File.join(RAILS_ROOT, 'config', 'routes.rb'))
1881

1882 1883
    @stat = stub_everything
  end
1884

1885 1886 1887 1888
  def teardown
    ActionController::Routing::Routes.configuration_files.clear
    Object.send :remove_const, :RAILS_ROOT
  end
1889

1890 1891 1892
  def test_load
    File.expects(:stat).returns(@stat)
    routes.expects(:load).with(regexp_matches(/routes\.rb$/))
1893

1894 1895
    routes.reload
  end
1896

1897 1898 1899 1900
  def test_no_reload_when_not_modified
    @stat.expects(:mtime).times(2).returns(1)
    File.expects(:stat).times(2).returns(@stat)
    routes.expects(:load).with(regexp_matches(/routes\.rb$/)).at_most_once
1901

1902 1903
    2.times { routes.reload }
  end
1904

1905 1906 1907 1908
  def test_reload_when_modified
    @stat.expects(:mtime).at_least(2).returns(1, 2)
    File.expects(:stat).at_least(2).returns(@stat)
    routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
1909

1910 1911
    2.times { routes.reload }
  end
1912

1913 1914 1915 1916
  def test_bang_forces_reload
    @stat.expects(:mtime).at_least(2).returns(1)
    File.expects(:stat).at_least(2).returns(@stat)
    routes.expects(:load).with(regexp_matches(/routes\.rb$/)).times(2)
1917

1918 1919
    2.times { routes.reload! }
  end
1920

1921 1922 1923
  def test_adding_inflections_forces_reload
    ActiveSupport::Inflector::Inflections.instance.expects(:uncountable).with('equipment')
    routes.expects(:reload!)
1924

1925 1926
    ActiveSupport::Inflector.inflections { |inflect| inflect.uncountable('equipment') }
  end
1927

1928 1929 1930 1931 1932
  def test_load_with_configuration
    routes.configuration_files.clear
    routes.add_configuration_file("foobarbaz")
    File.expects(:stat).returns(@stat)
    routes.expects(:load).with("foobarbaz")
1933

1934
    routes.reload
1935
  end
J
Joshua Peek 已提交
1936

1937 1938
  def test_load_multiple_configurations
    routes.add_configuration_file("engines.rb")
J
Joshua Peek 已提交
1939

1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951
    File.expects(:stat).at_least_once.returns(@stat)

    routes.expects(:load).with('./config/routes.rb')
    routes.expects(:load).with('engines.rb')

    routes.reload
  end

  private
    def routes
      ActionController::Routing::Routes
    end
1952
end