routing_test.rb 67.1 KB
Newer Older
1
# encoding: utf-8
2 3
require 'abstract_unit'
require 'controller/fake_controllers'
4
require 'active_support/core_ext/object/with_options'
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 = ActionDispatch::Routing
13

14
# See RFC 3986, section 3.3 for allowed path characters.
15
class UriReservedCharactersRoutingTest < Test::Unit::TestCase
16 17
  include RoutingTestHelpers

18
  def setup
19
    @set = ActionDispatch::Routing::RouteSet.new
20 21
    @set.draw do
      match ':controller/:action/:variable/*additional'
22
    end
23

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

27 28
    @segment = "#{safe.join}#{unsafe.join}".freeze
    @escaped = "#{safe.join}#{hex.join}".freeze
29
  end
30 31

  def test_route_generation_escapes_unsafe_path_characters
32
    assert_equal "/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2",
33 34 35 36 37 38
      url_for(@set, {
        :controller => "content",
        :action => "act#{@segment}ion",
        :variable => "var#{@segment}iable",
        :additional => ["add#{@segment}itional-1", "add#{@segment}itional-2"]
      })
39
  end
40 41

  def test_route_recognition_unescapes_path_components
42
    options = { :controller => "content",
43
                :action => "act#{@segment}ion",
44
                :variable => "var#{@segment}iable",
45
                :additional => "add#{@segment}itional-1/add#{@segment}itional-2" }
46
    assert_equal options, @set.recognize_path("/content/act#{@escaped}ion/var#{@escaped}iable/add#{@escaped}itional-1/add#{@escaped}itional-2")
47
  end
48 49

  def test_route_generation_allows_passing_non_string_values_to_generated_helper
50 51 52 53 54 55 56
    assert_equal "/content/action/variable/1/2",
      url_for(@set, {
        :controller => "content",
        :action => "action",
        :variable => "variable",
        :additional => [1, 2]
      })
57
  end
58 59
end

60
class MockController
61 62 63 64 65
  def self.build(helpers)
    Class.new do
      def url_for(options)
        options[:protocol] ||= "http"
        options[:host] ||= "test.host"
66

67 68 69 70 71
        super(options)
      end

      include helpers
    end
72
  end
73
end
74

75
class LegacyRouteSetTests < Test::Unit::TestCase
76 77
  include RoutingTestHelpers

78
  attr_reader :rs
79

80
  def setup
A
Aaron Patterson 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93
    @rs       = ::ActionDispatch::Routing::RouteSet.new
    @response = nil
  end

  def get(uri_or_host, path = nil, port = nil)
    host = uri_or_host.host unless path
    path ||= uri_or_host.path

    params = {'PATH_INFO'      => path,
              'REQUEST_METHOD' => 'GET',
              'HTTP_HOST'      => host}

    @rs.call(params)[2]
94
  end
J
Joshua Peek 已提交
95

96 97 98 99 100 101 102 103 104
  def test_regexp_precidence
    @rs.draw do
      match '/whois/:domain', :constraints => {
        :domain => /\w+\.[\w\.]+/ },
        :to     => lambda { |env| [200, {}, 'regexp'] }

      match '/whois/:id', :to => lambda { |env| [200, {}, 'id'] }
    end

A
Aaron Patterson 已提交
105 106
    assert_equal 'regexp', get(URI('http://example.org/whois/example.org'))
    assert_equal 'id', get(URI('http://example.org/whois/123'))
107 108
  end

A
Aaron Patterson 已提交
109 110 111 112 113 114 115 116 117 118 119 120 121 122
  def test_class_and_lambda_constraints
    subdomain = Class.new {
      def matches? request
        request.subdomain.present? and request.subdomain != 'clients'
      end
    }

    @rs.draw do
      match '/', :constraints => subdomain.new,
                 :to          => lambda { |env| [200, {}, 'default'] }
      match '/', :constraints => { :subdomain => 'clients' },
                 :to          => lambda { |env| [200, {}, 'clients'] }
    end

A
Aaron Patterson 已提交
123 124
    assert_equal 'default', get(URI('http://www.example.org/'))
    assert_equal 'clients', get(URI('http://clients.example.org/'))
A
Aaron Patterson 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137
  end

  def test_lambda_constraints
    @rs.draw do
      match '/', :constraints => lambda { |req|
        req.subdomain.present? and req.subdomain != "clients" },
                 :to          => lambda { |env| [200, {}, 'default'] }

      match '/', :constraints => lambda { |req|
        req.subdomain.present? && req.subdomain == "clients" },
                 :to          => lambda { |env| [200, {}, 'clients'] }
    end

A
Aaron Patterson 已提交
138 139
    assert_equal 'default', get(URI('http://www.example.org/'))
    assert_equal 'clients', get(URI('http://clients.example.org/'))
A
Aaron Patterson 已提交
140 141
  end

142 143 144 145 146 147
  def test_draw_with_block_arity_one_raises
    assert_raise(RuntimeError) do
      @rs.draw { |map| map.match '/:controller(/:action(/:id))' }
    end
  end

148
  def test_default_setup
149
    @rs.draw { match '/:controller(/:action(/:id))' }
150
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
151
    assert_equal({:controller => "content", :action => 'list'},  rs.recognize_path("/content/list"))
152 153 154 155
    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"))

156
    assert_equal '/admin/user/show/10', url_for(rs, { :controller => 'admin/user', :action => 'show', :id => 10 })
157

158 159
    assert_equal '/admin/user/show',    url_for(rs, { :action => 'show' }, { :controller => 'admin/user', :action => 'list', :id => '10' })
    assert_equal '/admin/user/list/10', url_for(rs, {}, { :controller => 'admin/user', :action => 'list', :id => '10' })
160

161 162
    assert_equal '/admin/stuff', url_for(rs, { :controller => 'stuff' }, { :controller => 'admin/user', :action => 'list', :id => '10' })
    assert_equal '/stuff',       url_for(rs, { :controller => '/stuff' }, { :controller => 'admin/user', :action => 'list', :id => '10' })
163 164 165 166
  end

  def test_ignores_leading_slash
    @rs.clear!
167
    @rs.draw { match '/:controller(/:action(/:id))'}
168 169 170 171 172
    test_default_setup
  end

  def test_time_recognition
    # We create many routes to make situation more realistic
173
    @rs = ::ActionDispatch::Routing::RouteSet.new
174
    @rs.draw {
175
      root :to => "search#new", :as => "frontpage"
176 177 178 179 180
      resources :videos do
        resources :comments
        resource  :file,      :controller => 'video_file'
        resource  :share,     :controller => 'video_shares'
        resource  :abuse,     :controller => 'video_abuses'
181
      end
182 183 184
      resources :abuses, :controller => 'video_abuses'
      resources :video_uploads
      resources :video_visits
185

186 187 188
      resources :users do
        resource  :settings
        resources :videos
189
      end
190 191
      resources :channels do
        resources :videos, :controller => 'channel_videos'
192
      end
193 194 195 196 197
      resource  :session
      resource  :lost_password
      match 'search' => 'search#index', :as => 'search'
      resources :pages
      match ':controller/:action/:id'
198 199
    }
  end
200

201
  def test_route_with_colon_first
202 203 204
    rs.draw do
      match '/:controller/:action/:id', :action => 'index', :id => nil
      match ':url', :controller => 'tiny_url', :action => 'translate'
205
    end
206 207 208
  end

  def test_route_with_regexp_for_controller
209
    rs.draw do
210 211
      match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/
      match '/:controller(/:action(/:id))'
212
    end
213

214 215
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
216 217 218 219 220
    assert_equal({:controller => "content", :action => "foo"},
        rs.recognize_path("/content/foo"))

    assert_equal '/admin/user/foo', url_for(rs, { :controller => "admin/user", :admintoken => "foo", :action => "index" })
    assert_equal '/content/foo',    url_for(rs, { :controller => "content", :action => "foo" })
221
  end
222

223
  def test_route_with_regexp_and_captures_for_controller
224
    rs.draw do
225
      match '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/
226 227 228
    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"))
229
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
230 231
  end

232
  def test_route_with_regexp_and_dot
233 234 235 236 237 238
    rs.draw do
      match ':controller/:action/:file',
                :controller => /admin|user/,
                :action => /upload|download/,
                :defaults => {:file => nil},
                :constraints => {:file => %r{[^/]+(\.[^/]+)?}}
239 240 241
    end
    # Without a file extension
    assert_equal '/user/download/file',
242 243 244
      url_for(rs, { :controller => "user", :action => "download", :file => "file" })

    assert_equal({:controller => "user", :action => "download", :file => "file"},
245
      rs.recognize_path("/user/download/file"))
246

247 248
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
249 250 251
      url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" })

    assert_equal({:controller => "user", :action => "download", :file => "file.jpg"},
252 253
      rs.recognize_path("/user/download/file.jpg"))
  end
254

255
  def test_basic_named_route
256
    rs.draw do
257
      root :to => 'content#list', :as => 'home'
258
    end
259
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
260
  end
261

262
  def test_named_route_with_option
263 264
    rs.draw do
      match 'page/:title' => 'content#show_page', :as => 'page'
265
    end
266

267
    assert_equal("http://test.host/page/new%20stuff",
268
        setup_for_named_route.send(:page_url, :title => 'new stuff'))
269
  end
270

271
  def test_named_route_with_default
272 273
    rs.draw do
      match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'
274
    end
275

276 277
    assert_equal("http://test.host/page/AboutRails",
        setup_for_named_route.send(:page_url, :title => "AboutRails"))
278
  end
279

280
  def test_named_route_with_path_prefix
281
    rs.draw do
282 283 284
      scope "my" do
        match 'page' => 'content#show_page', :as => 'page'
      end
285
    end
286

287
    assert_equal("http://test.host/my/page",
288
        setup_for_named_route.send(:page_url))
289
  end
290

291
  def test_named_route_with_blank_path_prefix
292
    rs.draw do
293 294 295
      scope "" do
        match 'page' => 'content#show_page', :as => 'page'
      end
296
    end
297

298
    assert_equal("http://test.host/page",
299
        setup_for_named_route.send(:page_url))
300 301
  end

302
  def test_named_route_with_nested_controller
303
    rs.draw do
304
      match 'admin/user' => 'admin/user#index', :as => "users"
305
    end
306

307
    assert_equal("http://test.host/admin/user",
308
        setup_for_named_route.send(:users_url))
309
  end
310

311
  def test_optimised_named_route_with_host
312
    rs.draw do
313
      match 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com'
314
    end
315 316 317 318 319 320 321 322 323
    routes = setup_for_named_route
    routes.expects(:url_for).with({
      :host => 'foo.com',
      :only_path => false,
      :controller => 'content',
      :action => 'show_page',
      :use_route => 'pages'
    }).once
    routes.send(:pages_url)
324
  end
325

326
  def setup_for_named_route
327
    MockController.build(rs.url_helpers).new
328
  end
329

330
  def test_named_route_without_hash
331 332
    rs.draw do
      match ':controller/:action/:id', :as => 'normal'
333
    end
334
  end
335

336
  def test_named_route_root
337 338
    rs.draw do
      root :to => "hello#index"
339
    end
340 341 342
    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("/", routes.send(:root_path))
343
  end
344

345
  def test_named_route_with_regexps
346 347
    rs.draw do
      match 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',
348
        :year => /\d+/, :month => /\d+/, :day => /\d+/
349
      match ':controller/:action/:id'
350
    end
351 352 353 354 355

    routes = setup_for_named_route

    assert_equal "http://test.host/page/2005/6/10/hi",
      routes.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
356
  end
357

358
  def test_changing_controller
359
    @rs.draw { match ':controller/:action/:id' }
360

361 362 363
    assert_equal '/admin/stuff/show/10',
        url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10},
                    {:controller => 'admin/user', :action => 'index'})
364
  end
365

366
  def test_paths_escaped
367 368 369
    rs.draw do
      match 'file/*path' => 'content#show_file', :as => 'path'
      match ':controller/:action/:id'
370
    end
371

372 373 374
    # 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"
375
    assert_equal 'hello+world/how+are+you?', results[:path]
376

377 378 379
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
380
    assert_equal 'hello world/how are you?', results[:path]
381
  end
382

383
  def test_paths_slashes_unescaped_with_ordered_parameters
384 385
    rs.draw do
      match '/file/*path' => 'content#index', :as => 'path'
386
    end
387

388
    # No / to %2F in URI, only for query params.
389
    assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world']))
390
  end
391

392
  def test_non_controllers_cannot_be_matched
393 394
    rs.draw do
      match ':controller/:action/:id'
395
    end
396
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
397
  end
398

399 400
  def test_should_list_options_diff_when_routing_constraints_dont_match
    rs.draw do
401
      match 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post'
402
    end
403 404 405
    assert_raise(ActionController::RoutingError) do
      url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" })
    end
406 407 408
  end

  def test_dynamic_path_allowed
409 410
    rs.draw do
      match '*path' => 'content#show_file'
411
    end
412

413 414
    assert_equal '/pages/boo',
        url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
415
  end
416

417
  def test_dynamic_recall_paths_allowed
418 419
    rs.draw do
      match '*path' => 'content#show_file'
420 421
    end

422 423
    assert_equal '/pages/boo',
        url_for(rs, {}, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
424
  end
425

426
  def test_backwards
427
    rs.draw do
428 429
      match 'page/:id(/:action)' => 'pages#show'
      match ':controller(/:action(/:id))'
430 431
    end

432 433 434
    assert_equal '/page/20',   url_for(rs, { :id => 20 }, { :controller => 'pages', :action => 'show' })
    assert_equal '/page/20',   url_for(rs, { :controller => 'pages', :id => 20, :action => 'show' })
    assert_equal '/pages/boo', url_for(rs, { :controller => 'pages', :action => 'boo' })
435 436 437
  end

  def test_route_with_fixnum_default
438
    rs.draw do
439
      match 'page(/:id)' => 'content#show_page', :id => 1
440
      match ':controller/:action/:id'
441 442
    end

443 444 445 446
    assert_equal '/page',    url_for(rs, { :controller => 'content', :action => 'show_page' })
    assert_equal '/page',    url_for(rs, { :controller => 'content', :action => 'show_page', :id => 1 })
    assert_equal '/page',    url_for(rs, { :controller => 'content', :action => 'show_page', :id => '1' })
    assert_equal '/page/10', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 10 })
447

448
    assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page"))
449 450 451 452 453 454
    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
455 456 457
    rs.draw do
      match 'page/:id' => 'content#show_page', :id => 1
      match ':controller/:action/:id'
458 459
    end

460 461
    assert_equal '/page/foo', url_for(rs, { :controller => 'content', :action => 'show_page', :id => 'foo' })
    assert_equal({ :controller => "content", :action => 'show_page', :id => 'foo' }, rs.recognize_path("/page/foo"))
462

R
R.T. Lechow 已提交
463
    token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in Russian
464
    token.force_encoding(Encoding::BINARY) if token.respond_to?(:force_encoding)
465
    escaped_token = CGI::escape(token)
466

467 468
    assert_equal '/page/' + escaped_token, url_for(rs, { :controller => 'content', :action => 'show_page', :id => token })
    assert_equal({ :controller => "content", :action => 'show_page', :id => token }, rs.recognize_path("/page/#{escaped_token}"))
469
  end
470

471
  def test_action_expiry
472
    @rs.draw { match ':controller(/:action(/:id))' }
473
    assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' })
474
  end
475

476
  def test_requirement_should_prevent_optional_id
477 478
    rs.draw do
      match 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'
479 480
    end

481
    assert_equal '/post/10', url_for(rs, { :controller => 'post', :action => 'show', :id => 10 })
482

483
    assert_raise ActionController::RoutingError do
484
      url_for(rs, { :controller => 'post', :action => 'show' })
485
    end
486
  end
487

488
  def test_both_requirement_and_optional
489
    rs.draw do
490
      match('test(/:year)' => 'post#show', :as => 'blog',
491
        :defaults => { :year => nil },
492
        :constraints => { :year => /\d{4}/ }
493
      )
494
      match ':controller/:action/:id'
495
    end
496

497 498
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' })
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil })
499

500
    assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url))
501
  end
502

503
  def test_set_to_nil_forgets
504
    rs.draw do
505
      match 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil
506
      match ':controller/:action/:id'
507 508
    end

509
    assert_equal '/pages/2005',
510
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 })
511
    assert_equal '/pages/2005/6',
512
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 })
513
    assert_equal '/pages/2005/6/12',
514
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 })
515

516
    assert_equal '/pages/2005/6/4',
517
      url_for(rs, { :day => 4 },   { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
518

519
    assert_equal '/pages/2005/6',
520
      url_for(rs, { :day => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
521

522
    assert_equal '/pages/2005',
523
      url_for(rs, { :day => nil, :month => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
524
  end
525

526
  def test_root_url_generation_with_controller_and_action
527
    rs.draw do
528
      root :to => "content#index"
529 530
    end

531 532
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
533
  end
534

535
  def test_named_root_url_generation_with_controller_and_action
536
    rs.draw do
537
       root :to => "content#index", :as => 'home'
538 539
    end

540 541
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
542

543
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
544
  end
545

546
  def test_named_route_method
547 548
    rs.draw do
      match 'categories' => 'content#categories', :as => 'categories'
549
      match ':controller(/:action(/:id))'
550 551
    end

552 553
    assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' })
    assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' })
554 555 556 557 558 559
  end

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

561
  def test_nil_defaults
562 563
    rs.draw do
      match 'journal' => 'content#list_journal',
564
        :date => nil, :user_id => nil
565
      match ':controller/:action/:id'
566
    end
567

568 569 570 571 572 573
    assert_equal '/journal', url_for(rs, {
      :controller => 'content',
      :action => 'list_journal',
      :date => nil,
      :user_id => nil
    })
574
  end
575

576
  def setup_request_method_routes_for(method)
577
    rs.draw do
578 579 580 581
      match '/match' => 'books#get', :via => :get
      match '/match' => 'books#post', :via => :post
      match '/match' => 'books#put', :via => :put
      match '/match' => 'books#delete', :via => :delete
582
    end
583
  end
584

585 586
  %w(GET POST PUT DELETE).each do |request_method|
    define_method("test_request_method_recognized_with_#{request_method}") do
587
      setup_request_method_routes_for(request_method)
J
Joshua Peek 已提交
588 589
      params = rs.recognize_path("/match", :method => request_method)
      assert_equal request_method.downcase, params[:action]
590 591
    end
  end
592

593
  def test_recognize_array_of_methods
594
    rs.draw do
595
      match '/match' => 'books#get_or_post', :via => [:get, :post]
596
      match '/match' => 'books#not_get_or_post'
597 598
    end

J
Joshua Peek 已提交
599 600
    params = rs.recognize_path("/match", :method => :post)
    assert_equal 'get_or_post', params[:action]
601

J
Joshua Peek 已提交
602 603
    params = rs.recognize_path("/match", :method => :put)
    assert_equal 'not_get_or_post', params[:action]
604
  end
605

606
  def test_subpath_recognized
607 608 609 610 611
    rs.draw do
      match '/books/:id/edit'    => 'subpath_books#edit'
      match '/items/:id/:action' => 'subpath_books'
      match '/posts/new/:action' => 'subpath_books'
      match '/posts/:id'         => 'subpath_books#show'
612 613
    end

614 615 616
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
617

618 619 620 621 622 623 624 625 626 627 628 629
    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]]
  end
630

631
  def test_subpath_generated
632 633 634 635
    rs.draw do
      match '/books/:id/edit'    => 'subpath_books#edit'
      match '/items/:id/:action' => 'subpath_books'
      match '/posts/new/:action' => 'subpath_books'
636 637
    end

638 639 640
    assert_equal "/books/7/edit",      url_for(rs, { :controller => "subpath_books", :id => 7, :action => "edit" })
    assert_equal "/items/15/complete", url_for(rs, { :controller => "subpath_books", :id => 15, :action => "complete" })
    assert_equal "/posts/new/preview", url_for(rs, { :controller => "subpath_books", :action => "preview" })
641
  end
642

643 644
  def test_failed_constraints_raises_exception_with_violated_constraints
    rs.draw do
645
      match 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ }
646 647
    end

648
    assert_raise(ActionController::RoutingError) do
649
      setup_for_named_route.send(:foo_with_requirement_url, "I am Against the constraints")
650 651
    end
  end
652

653
  def test_routes_changed_correctly_after_clear
654
    rs = ::ActionDispatch::Routing::RouteSet.new
655 656 657 658 659 660
    rs.draw do
      match 'ca' => 'ca#aa'
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
661 662
    end

663
    hash = rs.recognize_path "/cc"
664

665 666
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
667

668 669 670 671 672
    rs.draw do
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
673 674
    end

675
    hash = rs.recognize_path "/cc"
676

677 678 679 680
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
  end
end
681

682
class RouteSetTest < ActiveSupport::TestCase
683 684
  include RoutingTestHelpers

685 686 687
  def set
    @set ||= ROUTING::RouteSet.new
  end
688

689 690 691
  def request
    @request ||= ActionController::TestRequest.new
  end
692

693 694
  def default_route_set
    @default_route_set ||= begin
J
Joshua Peek 已提交
695
      set = ROUTING::RouteSet.new
696
      set.draw do
697
        match '/:controller(/:action(/:id))'
698 699 700 701 702
      end
      set
    end
  end

703
  def test_generate_extras
704
    set.draw { match ':controller/(:action(/:id))' }
705 706
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
707
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
708
  end
709

710
  def test_extra_keys
711
    set.draw { match ':controller/:action/:id' }
712
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
713
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
714
  end
715

716
  def test_generate_extras_not_first
717 718 719
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
720
    end
721 722
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
723
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
724
  end
725

726
  def test_generate_not_first
727 728 729
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
730
    end
731 732
    assert_equal "/foo/bar/15?this=hello",
        url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" })
733
  end
734

735
  def test_extra_keys_not_first
736 737 738
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
739
    end
740
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
741
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
742
  end
743

744 745
  def test_draw
    assert_equal 0, set.routes.size
746 747
    set.draw do
      match '/hello/world' => 'a#b'
748
    end
749 750
    assert_equal 1, set.routes.size
  end
751

752 753
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
754 755
    set.draw do
      match '/users/index' => 'users#index'
756
    end
757
    set.recognize_path('/users/index', :method => :get)
758 759 760
    assert_equal 1, set.routes.size
  end

761 762
  def test_named_draw
    assert_equal 0, set.routes.size
763 764
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
765
    end
766 767 768
    assert_equal 1, set.routes.size
    assert_equal set.routes.first, set.named_routes[:hello]
  end
769

770
  def test_earlier_named_routes_take_precedence
771 772 773
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
      match '/hello'       => 'a#b', :as => 'hello'
774
    end
775
    assert_equal set.routes.first, set.named_routes[:hello]
776
  end
777

778
  def setup_named_route_test
779
    set.draw do
780 781 782
      match '/people(/:id)' => 'people#show', :as => 'show'
      match '/people' => 'people#index', :as => 'index'
      match '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi'
783
      match '/admin/users' => 'admin/users#index', :as => "users"
784 785
    end

786
    MockController.build(set.url_helpers).new
787
  end
788

789 790 791 792
  def test_named_route_hash_access_method
    controller = setup_named_route_test

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

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

    assert_equal(
801
      { :controller => 'people', :action => 'show', :id => 5, :use_route => "show", :only_path => true },
802 803
      controller.send(:hash_for_show_path, :id => 5)
    )
804 805
  end

806 807
  def test_named_route_url_method
    controller = setup_named_route_test
808

809 810
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
811

812 813
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
814

815 816
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
817
    assert_equal '/admin/users', url_for(set, controller.send(:hash_for_users_url), { :controller => 'users', :action => 'index' })
818
  end
819

820 821
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
822

823 824
    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')
825

826 827
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
828

829 830
    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')
831

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

835 836
    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')
837

838 839 840
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
841

842 843 844 845
  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
846

847 848 849 850
  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
851

852 853 854 855
  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
856

857 858 859 860 861
  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
862

863 864 865 866 867
  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
868

869 870 871 872 873
  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
874

875 876 877 878 879
  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
880

881
  def test_draw_default_route
882 883
    set.draw do
      match '/:controller/:action/:id'
J
Joshua Peek 已提交
884
    end
885

J
Joshua Peek 已提交
886
    assert_equal 1, set.routes.size
887

888 889
    assert_equal '/users/show/10',  url_for(set, { :controller => 'users', :action => 'show', :id => 10 })
    assert_equal '/users/index/10', url_for(set, { :controller => 'users', :id => 10 })
890

J
Joshua Peek 已提交
891 892
    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/'))
893
  end
894

895
  def test_route_with_parameter_shell
896 897
    set.draw do
      match 'page/:id' => 'pages#show', :id => /\d+/
898
      match '/:controller(/:action(/:id))'
J
Joshua Peek 已提交
899
    end
900

J
Joshua Peek 已提交
901 902 903
    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'))
904

J
Joshua Peek 已提交
905 906
    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'))
907
  end
908

909 910 911 912 913 914 915 916
  def test_route_constraints_on_request_object_with_anchors_are_valid
    assert_nothing_raised do
      set.draw do
        match 'page/:id' => 'pages#show', :constraints => { :host => /^foo$/ }
      end
    end
  end

917
  def test_route_constraints_with_anchor_chars_are_invalid
918
    assert_raise ArgumentError do
919 920
      set.draw do
        match 'page/:id' => 'pages#show', :id => /^\d+/
921
      end
922
    end
923
    assert_raise ArgumentError do
924 925
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\A\d+/
926 927
      end
    end
928
    assert_raise ArgumentError do
929 930
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+$/
931 932
      end
    end
933
    assert_raise ArgumentError do
934 935
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\Z/
936 937
      end
    end
938
    assert_raise ArgumentError do
939 940
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\z/
941
      end
942 943
    end
  end
944

945
  def test_route_constraints_with_options_method_condition_is_valid
946
    assert_nothing_raised do
947
      set.draw do
948
        match 'valid/route' => 'pages#show', :via => :options
949 950 951 952
      end
    end
  end

953
  def test_recognize_with_encoded_id_and_regex
954 955
    set.draw do
      match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/
956
    end
957

958 959 960 961
    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

962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979
  def test_recognize_with_http_methods
    set.draw do
      get    "/people"     => "people#index", :as => "people"
      post   "/people"     => "people#create"
      get    "/people/:id" => "people#show",  :as => "person"
      put    "/people/:id" => "people#update"
      delete "/people/:id" => "people#destroy"
    end

    params = set.recognize_path("/people", :method => :get)
    assert_equal("index", params[:action])

    params = set.recognize_path("/people", :method => :post)
    assert_equal("create", params[:action])

    params = set.recognize_path("/people/5", :method => :put)
    assert_equal("update", params[:action])

980
    assert_raise(ActionController::UnknownHttpMethod) {
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
      set.recognize_path("/people", :method => :bacon)
    }

    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])

    params = set.recognize_path("/people/5", :method => :put)
    assert_equal("update", params[:action])
    assert_equal("5", params[:id])

    params = set.recognize_path("/people/5", :method => :delete)
    assert_equal("destroy", params[:action])
    assert_equal("5", params[:id])

    assert_raise(ActionController::RoutingError) {
      set.recognize_path("/people/5", :method => :post)
    }
  end

1001
  def test_recognize_with_alias_in_conditions
1002
    set.draw do
1003 1004
      match "/people" => 'people#index', :as => 'people', :via => :get
      root :to => "people#index"
1005
    end
1006

J
Joshua Peek 已提交
1007 1008 1009
    params = set.recognize_path("/people", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1010

J
Joshua Peek 已提交
1011 1012 1013
    params = set.recognize_path("/", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1014
  end
1015

1016
  def test_typo_recognition
1017 1018
    set.draw do
      match 'articles/:year/:month/:day/:title' => 'articles#permalink',
1019
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
1020
    end
1021

J
Joshua Peek 已提交
1022 1023 1024 1025 1026 1027
    params = set.recognize_path("/articles/2005/11/05/a-very-interesting-article", :method => :get)
    assert_equal("permalink", params[:action])
    assert_equal("2005", params[:year])
    assert_equal("11", params[:month])
    assert_equal("05", params[:day])
    assert_equal("a-very-interesting-article", params[:title])
1028
  end
1029

1030 1031
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
1032
    set.draw do
1033
      match '/profile' => 'profile#index'
1034 1035
    end

1036
    set.recognize_path("/profile") rescue nil
1037

1038 1039 1040 1041
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
1042
    set.draw do
1043 1044
      get "people/:id" => "people#show", :as => "person"
      put "people/:id" => "people#update"
1045
      get "people/:id(.:format)" => "people#show"
1046 1047
    end

J
Joshua Peek 已提交
1048 1049 1050
    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1051

J
Joshua Peek 已提交
1052 1053
    params = set.recognize_path("/people/5", :method => :put)
    assert_equal("update", params[:action])
1054

J
Joshua Peek 已提交
1055 1056 1057
    params = set.recognize_path("/people/5.png", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1058
    assert_equal("png", params[:format])
1059 1060 1061
  end

  def test_generate_with_default_action
1062
    set.draw do
1063
      match "/people", :controller => "people", :action => "index"
1064
      match "/people/list", :controller => "people", :action => "list"
1065 1066
    end

1067
    url = url_for(set, { :controller => "people", :action => "list" })
1068 1069
    assert_equal "/people/list", url
  end
1070

1071
  def test_root_map
1072
    set.draw { root :to => 'people#index' }
1073

J
Joshua Peek 已提交
1074 1075 1076
    params = set.recognize_path("", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1077 1078 1079
  end

  def test_namespace
1080
    set.draw do
1081

1082 1083
      namespace 'api' do
        match 'inventory' => 'products#inventory'
1084
      end
1085

1086 1087
    end

J
Joshua Peek 已提交
1088 1089 1090
    params = set.recognize_path("/api/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1091
  end
1092

1093
  def test_namespaced_root_map
1094 1095
    set.draw do
      namespace 'api' do
1096
        root :to => 'products#index'
1097 1098 1099
      end
    end

J
Joshua Peek 已提交
1100 1101 1102
    params = set.recognize_path("/api", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("index", params[:action])
1103
  end
1104

1105
  def test_namespace_with_path_prefix
1106
    set.draw do
1107
      scope :module => "api", :path => "prefix" do
1108
        match 'inventory' => 'products#inventory'
1109
      end
1110 1111
    end

J
Joshua Peek 已提交
1112 1113 1114
    params = set.recognize_path("/prefix/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1115
  end
1116

1117
  def test_namespace_with_blank_path_prefix
1118
    set.draw do
1119
      scope :module => "api", :path => "" do
1120
        match 'inventory' => 'products#inventory'
1121 1122 1123
      end
    end

J
Joshua Peek 已提交
1124 1125 1126
    params = set.recognize_path("/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1127 1128
  end

1129
  def test_generate_changes_controller_module
1130
    set.draw { match ':controller/:action/:id' }
1131
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
1132 1133 1134

    assert_equal "/foo/bar/baz/7",
        url_for(set, { :controller => "foo/bar", :action => "baz", :id => 7 }, current)
1135 1136 1137
  end

  def test_id_is_sticky_when_it_ought_to_be
1138 1139
    set.draw do
      match ':controller/:id/:action'
1140
    end
1141

1142
    url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" })
1143 1144
    assert_equal "/people/7/destroy", url
  end
1145

1146
  def test_use_static_path_when_possible
1147 1148 1149
    set.draw do
      match 'about' => "welcome#about"
      match ':controller/:action/:id'
1150 1151
    end

1152 1153 1154
    url = url_for(set, { :controller => "welcome", :action => "about" },
      { :controller => "welcome", :action => "get", :id => "7" })

1155 1156
    assert_equal "/about", url
  end
1157

1158
  def test_generate
1159
    set.draw { match ':controller/:action/:id' }
1160

1161
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1162
    assert_equal "/foo/bar/7?x=y",     url_for(set, args)
1163 1164 1165
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1166

1167
  def test_generate_with_path_prefix
1168 1169 1170 1171 1172
    set.draw do
      scope "my" do
        match ':controller(/:action(/:id))'
      end
    end
1173

1174
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1175
    assert_equal "/my/foo/bar/7?x=y", url_for(set, args)
1176 1177
  end

1178
  def test_generate_with_blank_path_prefix
1179 1180 1181 1182 1183
    set.draw do
      scope "" do
        match ':controller(/:action(/:id))'
      end
    end
1184 1185

    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1186
    assert_equal "/foo/bar/7?x=y", url_for(set, args)
1187 1188
  end

1189
  def test_named_routes_are_never_relative_to_modules
1190
    set.draw do
1191 1192 1193
      match "/connection/manage(/:action)" => 'connection/manage#index'
      match "/connection/connection" => "connection/connection#index"
      match '/connection' => 'connection#index', :as => 'family_connection'
1194
    end
1195

1196
    url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' })
1197 1198
    assert_equal "/connection/connection", url

1199
    url = url_for(set, { :use_route => :family_connection, :controller => "connection" }, { :controller => 'connection/manage' })
1200 1201 1202 1203
    assert_equal "/connection", url
  end

  def test_action_left_off_when_id_is_recalled
1204
    set.draw do
1205
      match ':controller(/:action(/:id))'
1206
    end
1207
    assert_equal '/books', url_for(set,
1208 1209
      {:controller => 'books', :action => 'index'},
      {:controller => 'books', :action => 'show', :id => '10'}
1210 1211
    )
  end
1212

1213
  def test_query_params_will_be_shown_when_recalled
1214 1215
    set.draw do
      match 'show_weblog/:parameter' => 'weblog#show'
1216
      match ':controller(/:action(/:id))'
1217
    end
1218
    assert_equal '/weblog/edit?parameter=1', url_for(set,
1219
      {:action => 'edit', :parameter => 1},
1220
      {:controller => 'weblog', :action => 'show', :parameter => 1}
1221 1222
    )
  end
1223

1224
  def test_format_is_not_inherit
1225
    set.draw do
1226
      match '/posts(.:format)' => 'posts#index'
1227 1228
    end

1229
    assert_equal '/posts', url_for(set,
1230 1231 1232 1233
      {:controller => 'posts'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )

1234
    assert_equal '/posts.xml', url_for(set,
1235 1236 1237 1238 1239
      {:controller => 'posts', :format => 'xml'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )
  end

1240
  def test_expiry_determination_should_consider_values_with_to_param
1241
    set.draw { match 'projects/:project_id/:controller/:action' }
1242 1243 1244
    assert_equal '/projects/1/weblog/show', url_for(set,
      { :action => 'show', :project_id => 1 },
      { :controller => 'weblog', :action => 'show', :project_id => '1' })
1245
  end
1246

1247
  def test_named_route_in_nested_resource
1248 1249
    set.draw do
      resources :projects do
1250 1251 1252
        member do
          match 'milestones' => 'milestones#index', :as => 'milestones'
        end
1253 1254
      end
    end
1255

J
Joshua Peek 已提交
1256 1257 1258
    params = set.recognize_path("/projects/1/milestones", :method => :get)
    assert_equal("milestones", params[:controller])
    assert_equal("index", params[:action])
1259
  end
1260

1261 1262
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
1263 1264
      set.draw do
        namespace :admin do
1265
          root :to => "home#index"
1266 1267 1268
        end
      end
    end
1269
  end
1270

1271 1272
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
1273 1274
      set.draw do
        namespace 'admin' do
1275
          root :to => "home#index"
1276 1277 1278
        end
      end
    end
1279
  end
1280

1281
  def test_route_constraints_with_unsupported_regexp_options_must_error
1282
    assert_raise ArgumentError do
1283 1284
      set.draw do
        match 'page/:name' => 'pages#show',
1285
          :constraints => { :name => /(david|jamis)/m }
1286
      end
1287
    end
1288
  end
1289

1290
  def test_route_constraints_with_supported_options_must_not_error
1291
    assert_nothing_raised do
1292
      set.draw do
1293
        match 'page/:name' => 'pages#show',
1294
          :constraints => { :name => /(david|jamis)/i }
1295 1296
      end
    end
1297
    assert_nothing_raised do
1298 1299
      set.draw do
        match 'page/:name' => 'pages#show',
1300
          :constraints => { :name => / # Desperately overcommented regexp
1301 1302 1303 1304
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
1305
                                      )/x }
1306 1307
      end
    end
1308
  end
1309

1310
  def test_route_requirement_recognize_with_ignore_case
1311 1312 1313
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1314 1315
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1316
    assert_raise ActionController::RoutingError do
1317
      set.recognize_path('/page/davidjamis')
1318
    end
1319 1320
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1321

1322
  def test_route_requirement_generate_with_ignore_case
1323 1324 1325
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1326
    end
1327

1328
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' })
J
Jeremy Kemper 已提交
1329 1330
    assert_equal "/page/david", url
    assert_raise ActionController::RoutingError do
1331
      url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' })
J
Jeremy Kemper 已提交
1332
    end
1333
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
J
Jeremy Kemper 已提交
1334
    assert_equal "/page/JAMIS", url
1335
  end
J
Jeremy Kemper 已提交
1336

1337
  def test_route_requirement_recognize_with_extended_syntax
1338 1339 1340
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => / # Desperately overcommented regexp
1341 1342 1343 1344 1345 1346 1347 1348
                                    ( #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'))
1349
    assert_raise ActionController::RoutingError do
1350 1351
      set.recognize_path('/page/david #The Creator')
    end
1352
    assert_raise ActionController::RoutingError do
1353
      set.recognize_path('/page/David')
1354 1355
    end
  end
1356

1357
  def test_route_requirement_with_xi_modifiers
1358
    set.draw do
1359
      match 'page/:name' => 'pages#show',
1360
        :constraints => {:name => / # Desperately overcommented regexp
1361 1362 1363 1364 1365
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1366
    end
1367

1368 1369
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'},
        set.recognize_path('/page/JAMIS'))
1370

1371 1372
    assert_equal "/page/JAMIS",
        url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
1373
  end
1374 1375

  def test_routes_with_symbols
1376 1377 1378
    set.draw do
      match 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol
      match 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named
1379 1380 1381 1382 1383
    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

1384
  def test_regexp_chunk_should_add_question_mark_for_optionals
1385 1386 1387
    set.draw do
      match '/' => 'foo#index'
      match '/hello' => 'bar#index'
J
Joshua Peek 已提交
1388
    end
1389

1390 1391
    assert_equal '/',      url_for(set, { :controller => 'foo' })
    assert_equal '/hello', url_for(set, { :controller => 'bar' })
1392

J
Joshua Peek 已提交
1393 1394
    assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/'))
    assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello'))
1395 1396 1397
  end

  def test_assign_route_options_with_anchor_chars
1398 1399
    set.draw do
      match '/cars/:action/:person/:car/', :controller => 'cars'
J
Joshua Peek 已提交
1400
    end
1401

1402
    assert_equal '/cars/buy/1/2', url_for(set, { :controller => 'cars', :action => 'buy', :person => '1', :car => '2' })
1403

J
Joshua Peek 已提交
1404
    assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2'))
1405 1406 1407
  end

  def test_segmentation_of_dot_path
1408 1409
    set.draw do
      match '/books/:action.rss', :controller => 'books'
J
Joshua Peek 已提交
1410
    end
1411

1412
    assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list' })
1413

J
Joshua Peek 已提交
1414
    assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss'))
1415 1416 1417
  end

  def test_segmentation_of_dynamic_dot_path
1418
    set.draw do
1419
      match '/books(/:action(.:format))', :controller => 'books'
J
Joshua Peek 已提交
1420
    end
1421

1422 1423 1424 1425
    assert_equal '/books/list.rss', url_for(set, { :controller => 'books', :action => 'list', :format => 'rss' })
    assert_equal '/books/list.xml', url_for(set, { :controller => 'books', :action => 'list', :format => 'xml' })
    assert_equal '/books/list',     url_for(set, { :controller => 'books', :action => 'list' })
    assert_equal '/books',          url_for(set, { :controller => 'books', :action => 'index' })
1426

J
Joshua Peek 已提交
1427 1428
    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'))
1429
    assert_equal({:controller => "books", :action => "list"},  set.recognize_path('/books/list'))
J
Joshua Peek 已提交
1430
    assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
1431 1432 1433
  end

  def test_slashes_are_implied
1434 1435
    @set = nil
    set.draw { match("/:controller(/:action(/:id))") }
1436

1437 1438 1439
    assert_equal '/content',        url_for(set, { :controller => 'content', :action => 'index' })
    assert_equal '/content/list',   url_for(set, { :controller => 'content', :action => 'list' })
    assert_equal '/content/show/1', url_for(set, { :controller => 'content', :action => 'show', :id => '1' })
1440

1441 1442
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content'))
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index'))
1443
    assert_equal({:controller => "content", :action => "list"},  set.recognize_path('/content/list'))
1444
    assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1'))
1445 1446 1447
  end

  def test_default_route_recognition
J
Joshua Peek 已提交
1448 1449 1450
    expected = {:controller => 'pages', :action => 'show', :id => '10'}
    assert_equal expected, default_route_set.recognize_path('/pages/show/10')
    assert_equal expected, default_route_set.recognize_path('/pages/show/10/')
1451 1452

    expected[:id] = 'jamis'
J
Joshua Peek 已提交
1453
    assert_equal expected, default_route_set.recognize_path('/pages/show/jamis/')
1454 1455

    expected.delete :id
J
Joshua Peek 已提交
1456 1457
    assert_equal expected, default_route_set.recognize_path('/pages/show')
    assert_equal expected, default_route_set.recognize_path('/pages/show/')
1458 1459

    expected[:action] = 'index'
J
Joshua Peek 已提交
1460 1461
    assert_equal expected, default_route_set.recognize_path('/pages/')
    assert_equal expected, default_route_set.recognize_path('/pages')
1462 1463

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
J
Joshua Peek 已提交
1464
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
1465 1466 1467
  end

  def test_default_route_should_omit_default_action
1468
    assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' })
1469 1470 1471
  end

  def test_default_route_should_include_default_action_when_id_present
1472
    assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' })
1473 1474 1475
  end

  def test_default_route_should_work_with_action_but_no_id
1476
    assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' })
1477 1478 1479
  end

  def test_default_route_should_uri_escape_pluses
J
Joshua Peek 已提交
1480 1481
    expected = { :controller => 'pages', :action => 'show', :id => 'hello world' }
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world')
1482
    assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected)
1483 1484

    expected[:id] = 'hello+world'
J
Joshua Peek 已提交
1485 1486
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world')
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld')
1487
    assert_equal '/pages/show/hello+world', url_for(default_route_set, expected)
1488 1489 1490
  end

  def test_build_empty_query_string
1491
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' })
1492 1493 1494
  end

  def test_build_query_string_with_nil_value
1495
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil })
1496 1497 1498
  end

  def test_simple_build_query_string
1499
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' })
1500 1501 1502
  end

  def test_convert_ints_build_query_string
1503
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 })
1504 1505 1506
  end

  def test_escape_spaces_build_query_string
1507
    assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' })
1508 1509 1510
  end

  def test_expand_array_build_query_string
1511
    assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] })
1512 1513 1514
  end

  def test_escape_spaces_build_query_string_selected_keys
1515
    assert_uri_equal '/foo?x=hello+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world' })
1516
  end
J
Joshua Peek 已提交
1517

1518
  def test_generate_with_default_params
1519
    set.draw do
1520 1521 1522
      match 'dummy/page/:page' => 'dummy#show'
      match 'dummy/dots/page.:page' => 'dummy#dots'
      match 'ibocorp(/:page)' => 'ibocorp#show',
1523 1524
                             :constraints => { :page => /\d+/ },
                             :defaults => { :page => 1 }
1525

1526
      match ':controller/:action/:id'
1527 1528
    end

1529
    assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 })
1530 1531
  end

1532
  def test_generate_with_optional_params_recalls_last_request
1533 1534
    set.draw do
      match "blog/", :controller => "blog", :action => "index"
1535

1536
      match "blog(/:year(/:month(/:day)))",
1537 1538 1539 1540
            :controller => "blog",
            :action => "show_date",
            :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ },
            :day => nil, :month => nil
1541

1542
      match "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/
1543
      match "blog/:controller/:action(/:id)"
1544
      match "*anything", :controller => "blog", :action => "unknown_request"
1545 1546 1547 1548
    end

    assert_equal({:controller => "blog", :action => "index"}, set.recognize_path("/blog"))
    assert_equal({:controller => "blog", :action => "show", :id => "123"}, set.recognize_path("/blog/show/123"))
1549 1550
    assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :day => nil, :month => nil }, set.recognize_path("/blog/2004"))
    assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :month => "12", :day => nil }, set.recognize_path("/blog/2004/12"))
1551 1552 1553
    assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :month => "12", :day => "25"}, set.recognize_path("/blog/2004/12/25"))
    assert_equal({:controller => "articles", :action => "edit", :id => "123"}, set.recognize_path("/blog/articles/edit/123"))
    assert_equal({:controller => "articles", :action => "show_stats"}, set.recognize_path("/blog/articles/show_stats"))
1554 1555
    assert_equal({:controller => "blog", :action => "unknown_request", :anything => "blog/wibble"}, set.recognize_path("/blog/wibble"))
    assert_equal({:controller => "blog", :action => "unknown_request", :anything => "junk"}, set.recognize_path("/junk"))
1556 1557 1558

    last_request = set.recognize_path("/blog/2006/07/28").freeze
    assert_equal({:controller => "blog",  :action => "show_date", :year => "2006", :month => "07", :day => "28"}, last_request)
1559 1560 1561 1562 1563
    assert_equal("/blog/2006/07/25", url_for(set, { :day => 25 }, last_request))
    assert_equal("/blog/2005",       url_for(set, { :year => 2005 }, last_request))
    assert_equal("/blog/show/123",   url_for(set, { :action => "show" , :id => 123 }, last_request))
    assert_equal("/blog/2006",       url_for(set, { :year => 2006 }, last_request))
    assert_equal("/blog/2006",       url_for(set, { :year => 2006, :month => nil }, last_request))
1564 1565
  end

J
Joshua Peek 已提交
1566 1567 1568 1569 1570 1571 1572 1573 1574 1575
  private
    def assert_uri_equal(expected, actual)
      assert_equal(sort_query_string_params(expected), sort_query_string_params(actual))
    end

    def sort_query_string_params(uri)
      path, qs = uri.split('?')
      qs = qs.split('&').sort.join('&') if qs
      qs ? "#{path}?#{qs}" : path
    end
1576
end
1577

1578
class RackMountIntegrationTests < ActiveSupport::TestCase
1579 1580
  include RoutingTestHelpers

1581 1582
  Model = Struct.new(:to_param)

1583 1584
  Mapping = lambda {
    namespace :admin do
1585
      resources :users, :posts
1586 1587
    end

1588
    namespace 'api' do
1589
      root :to => 'users#index'
1590 1591
    end

1592
    match '/blog(/:year(/:month(/:day)))' => 'posts#show_date',
1593
      :constraints => {
1594 1595 1596 1597 1598 1599
        :year => /(19|20)\d\d/,
        :month => /[01]?\d/,
        :day => /[0-3]?\d/
      },
      :day => nil,
      :month => nil
1600

1601
    match 'archive/:year', :controller => 'archive', :action => 'index',
1602
      :defaults => { :year => nil },
1603 1604
      :constraints => { :year => /\d{4}/ },
      :as => "blog"
1605

1606
    resources :people
1607
    match 'legacy/people' => "people#index", :legacy => "true"
1608

1609
    match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol
1610 1611 1612 1613 1614 1615 1616 1617
    match 'id_default(/:id)' => "foo#id_default", :id => 1
    match 'get_or_post' => "foo#get_or_post", :via => [:get, :post]
    match 'optional/:optional' => "posts#index"
    match 'projects/:project_id' => "project#index", :as => "project"
    match 'clients' => "projects#index"

    match 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i
    match 'extended/geocode/:postalcode' => 'geocode#show',:constraints => {
1618 1619 1620 1621
                  :postalcode => /# Postcode format
                                  \d{5} #Prefix
                                  (-\d{4})? #Suffix
                                  /x
1622
                  }, :as => "geocode"
1623

1624
    match 'news(.:format)' => "news#index"
1625

Ł
Łukasz Strzałkowski 已提交
1626
    match 'comment/:id(/:action)' => "comments#show"
1627 1628 1629
    match 'ws/:controller(/:action(/:id))', :ws => true
    match 'account(/:action)' => "account#subscription"
    match 'pages/:page_id/:controller(/:action(/:id))'
1630
    match ':controller/ping', :action => 'ping'
1631 1632
    match ':controller(/:action(/:id))(.:format)'
    root :to => "news#index"
1633 1634 1635
  }

  def setup
1636
    @routes = ActionDispatch::Routing::RouteSet.new
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
    @routes.draw(&Mapping)
  end

  def test_recognize_path
    assert_equal({:controller => 'admin/users', :action => 'index'}, @routes.recognize_path('/admin/users', :method => :get))
    assert_equal({:controller => 'admin/users', :action => 'create'}, @routes.recognize_path('/admin/users', :method => :post))
    assert_equal({:controller => 'admin/users', :action => 'new'}, @routes.recognize_path('/admin/users/new', :method => :get))
    assert_equal({:controller => 'admin/users', :action => 'show', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :get))
    assert_equal({:controller => 'admin/users', :action => 'update', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :put))
    assert_equal({:controller => 'admin/users', :action => 'destroy', :id => '1'}, @routes.recognize_path('/admin/users/1', :method => :delete))
    assert_equal({:controller => 'admin/users', :action => 'edit', :id => '1'}, @routes.recognize_path('/admin/users/1/edit', :method => :get))

    assert_equal({:controller => 'admin/posts', :action => 'index'}, @routes.recognize_path('/admin/posts', :method => :get))
    assert_equal({:controller => 'admin/posts', :action => 'new'}, @routes.recognize_path('/admin/posts/new', :method => :get))

    assert_equal({:controller => 'api/users', :action => 'index'}, @routes.recognize_path('/api', :method => :get))
    assert_equal({:controller => 'api/users', :action => 'index'}, @routes.recognize_path('/api/', :method => :get))

1655 1656
    assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => nil, :day => nil }, @routes.recognize_path('/blog/2009', :method => :get))
    assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01', :day => nil }, @routes.recognize_path('/blog/2009/01', :method => :get))
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675
    assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01', :day => '01'}, @routes.recognize_path('/blog/2009/01/01', :method => :get))

    assert_equal({:controller => 'archive', :action => 'index', :year => '2010'}, @routes.recognize_path('/archive/2010'))
    assert_equal({:controller => 'archive', :action => 'index'}, @routes.recognize_path('/archive'))

    assert_equal({:controller => 'people', :action => 'index'}, @routes.recognize_path('/people', :method => :get))
    assert_equal({:controller => 'people', :action => 'index', :format => 'xml'}, @routes.recognize_path('/people.xml', :method => :get))
    assert_equal({:controller => 'people', :action => 'create'}, @routes.recognize_path('/people', :method => :post))
    assert_equal({:controller => 'people', :action => 'new'}, @routes.recognize_path('/people/new', :method => :get))
    assert_equal({:controller => 'people', :action => 'show', :id => '1'}, @routes.recognize_path('/people/1', :method => :get))
    assert_equal({:controller => 'people', :action => 'show', :id => '1', :format => 'xml'}, @routes.recognize_path('/people/1.xml', :method => :get))
    assert_equal({:controller => 'people', :action => 'update', :id => '1'}, @routes.recognize_path('/people/1', :method => :put))
    assert_equal({:controller => 'people', :action => 'destroy', :id => '1'}, @routes.recognize_path('/people/1', :method => :delete))
    assert_equal({:controller => 'people', :action => 'edit', :id => '1'}, @routes.recognize_path('/people/1/edit', :method => :get))
    assert_equal({:controller => 'people', :action => 'edit', :id => '1', :format => 'xml'}, @routes.recognize_path('/people/1/edit.xml', :method => :get))

    assert_equal({:controller => 'symbols', :action => 'show', :name => :as_symbol}, @routes.recognize_path('/symbols'))
    assert_equal({:controller => 'foo', :action => 'id_default', :id => '1'}, @routes.recognize_path('/id_default/1'))
    assert_equal({:controller => 'foo', :action => 'id_default', :id => '2'}, @routes.recognize_path('/id_default/2'))
1676
    assert_equal({:controller => 'foo', :action => 'id_default', :id => 1 }, @routes.recognize_path('/id_default'))
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
    assert_equal({:controller => 'foo', :action => 'get_or_post'}, @routes.recognize_path('/get_or_post', :method => :get))
    assert_equal({:controller => 'foo', :action => 'get_or_post'}, @routes.recognize_path('/get_or_post', :method => :post))
    assert_raise(ActionController::ActionControllerError) { @routes.recognize_path('/get_or_post', :method => :put) }
    assert_raise(ActionController::ActionControllerError) { @routes.recognize_path('/get_or_post', :method => :delete) }

    assert_equal({:controller => 'posts', :action => 'index', :optional => 'bar'}, @routes.recognize_path('/optional/bar'))
    assert_raise(ActionController::ActionControllerError) { @routes.recognize_path('/optional') }

    assert_equal({:controller => 'posts', :action => 'show', :id => '1', :ws => true}, @routes.recognize_path('/ws/posts/show/1', :method => :get))
    assert_equal({:controller => 'posts', :action => 'list', :ws => true}, @routes.recognize_path('/ws/posts/list', :method => :get))
    assert_equal({:controller => 'posts', :action => 'index', :ws => true}, @routes.recognize_path('/ws/posts', :method => :get))

    assert_equal({:controller => 'account', :action => 'subscription'}, @routes.recognize_path('/account', :method => :get))
    assert_equal({:controller => 'account', :action => 'subscription'}, @routes.recognize_path('/account/subscription', :method => :get))
    assert_equal({:controller => 'account', :action => 'billing'}, @routes.recognize_path('/account/billing', :method => :get))

    assert_equal({:page_id => '1', :controller => 'notes', :action => 'index'}, @routes.recognize_path('/pages/1/notes', :method => :get))
    assert_equal({:page_id => '1', :controller => 'notes', :action => 'list'}, @routes.recognize_path('/pages/1/notes/list', :method => :get))
    assert_equal({:page_id => '1', :controller => 'notes', :action => 'show', :id => '2'}, @routes.recognize_path('/pages/1/notes/show/2', :method => :get))

    assert_equal({:controller => 'posts', :action => 'ping'}, @routes.recognize_path('/posts/ping', :method => :get))
    assert_equal({:controller => 'posts', :action => 'index'}, @routes.recognize_path('/posts', :method => :get))
    assert_equal({:controller => 'posts', :action => 'index'}, @routes.recognize_path('/posts/index', :method => :get))
    assert_equal({:controller => 'posts', :action => 'show'}, @routes.recognize_path('/posts/show', :method => :get))
    assert_equal({:controller => 'posts', :action => 'show', :id => '1'}, @routes.recognize_path('/posts/show/1', :method => :get))
    assert_equal({:controller => 'posts', :action => 'create'}, @routes.recognize_path('/posts/create', :method => :post))

    assert_equal({:controller => 'geocode', :action => 'show', :postalcode => 'hx12-1az'}, @routes.recognize_path('/ignorecase/geocode/hx12-1az'))
    assert_equal({:controller => 'geocode', :action => 'show', :postalcode => 'hx12-1AZ'}, @routes.recognize_path('/ignorecase/geocode/hx12-1AZ'))
    assert_equal({:controller => 'geocode', :action => 'show', :postalcode => '12345-1234'}, @routes.recognize_path('/extended/geocode/12345-1234'))
    assert_equal({:controller => 'geocode', :action => 'show', :postalcode => '12345'}, @routes.recognize_path('/extended/geocode/12345'))

1709
    assert_equal({:controller => 'news', :action => 'index' }, @routes.recognize_path('/', :method => :get))
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
    assert_equal({:controller => 'news', :action => 'index', :format => 'rss'}, @routes.recognize_path('/news.rss', :method => :get))

    assert_raise(ActionController::RoutingError) { @routes.recognize_path('/none', :method => :get) }
  end

  def test_generate_extras
    assert_equal ['/people', []], @routes.generate_extras(:controller => 'people')
    assert_equal ['/people', [:foo]], @routes.generate_extras(:controller => 'people', :foo => 'bar')
    assert_equal ['/people', []], @routes.generate_extras(:controller => 'people', :action => 'index')
    assert_equal ['/people', [:foo]], @routes.generate_extras(:controller => 'people', :action => 'index', :foo => 'bar')
    assert_equal ['/people/new', []], @routes.generate_extras(:controller => 'people', :action => 'new')
    assert_equal ['/people/new', [:foo]], @routes.generate_extras(:controller => 'people', :action => 'new', :foo => 'bar')
    assert_equal ['/people/1', []], @routes.generate_extras(:controller => 'people', :action => 'show', :id => '1')
    assert_equal ['/people/1', [:bar, :foo]], sort_extras!(@routes.generate_extras(:controller => 'people', :action => 'show', :id => '1', :foo => '2', :bar => '3'))
    assert_equal ['/people', [:person]], @routes.generate_extras(:controller => 'people', :action => 'create', :person => { :first_name => 'Josh', :last_name => 'Peek' })
    assert_equal ['/people', [:people]], @routes.generate_extras(:controller => 'people', :action => 'create', :people => ['Josh', 'Dave'])

    assert_equal ['/posts/show/1', []], @routes.generate_extras(:controller => 'posts', :action => 'show', :id => '1')
    assert_equal ['/posts/show/1', [:bar, :foo]], sort_extras!(@routes.generate_extras(:controller => 'posts', :action => 'show', :id => '1', :foo => '2', :bar => '3'))
    assert_equal ['/posts', []], @routes.generate_extras(:controller => 'posts', :action => 'index')
    assert_equal ['/posts', [:foo]], @routes.generate_extras(:controller => 'posts', :action => 'index', :foo => 'bar')
  end

  def test_extras
    params = {:controller => 'people'}
    assert_equal [], @routes.extra_keys(params)
    assert_equal({:controller => 'people'}, params)

    params = {:controller => 'people', :foo => 'bar'}
    assert_equal [:foo], @routes.extra_keys(params)
    assert_equal({:controller => 'people', :foo => 'bar'}, params)

    params = {:controller => 'people', :action => 'create', :person => { :name => 'Josh'}}
    assert_equal [:person], @routes.extra_keys(params)
    assert_equal({:controller => 'people', :action => 'create', :person => { :name => 'Josh'}}, params)
  end

  private
    def sort_extras!(extras)
      if extras.length == 2
        extras[1].sort! { |a, b| a.to_s <=> b.to_s }
      end
      extras
    end

    def assert_raise(e)
      result = yield
      flunk "Did not raise #{e}, but returned #{result.inspect}"
    rescue e
      assert true
    end
end