routing_test.rb 71.9 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
require 'active_support/core_ext/object/json'
6

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

12
ROUTING = ActionDispatch::Routing
13

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

18
  def setup
19
    @set = ActionDispatch::Routing::RouteSet.new
20
    @set.draw do
21
      get ':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
  def self.build(helpers, additional_options = {})
62
    Class.new do
63 64
      define_method :url_options do
        options = super()
65 66
        options[:protocol] ||= "http"
        options[:host] ||= "test.host"
67
        options.merge(additional_options)
68 69 70 71
      end

      include helpers
    end
72
  end
73
end
74

75
class LegacyRouteSetTests < ActiveSupport::TestCase
76
  include RoutingTestHelpers
77
  include ActionDispatch::RoutingVerbs
78

79
  attr_reader :rs
80
  alias :routes :rs
81

82
  def setup
A
Aaron Patterson 已提交
83 84 85 86
    @rs       = ::ActionDispatch::Routing::RouteSet.new
    @response = nil
  end

87 88
  def test_symbols_with_dashes
    rs.draw do
89
      get '/:artist/:song-omg', :to => lambda { |env|
90
        resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
91 92 93 94
        [200, {}, [resp]]
      }
    end

95
    hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/faithfully-omg'))
96 97 98 99 100
    assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
  end

  def test_id_with_dash
    rs.draw do
101
      get '/journey/:id', :to => lambda { |env|
102
        resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
103 104 105 106
        [200, {}, [resp]]
      }
    end

107
    hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/faithfully-omg'))
108 109 110 111 112
    assert_equal({"id"=>"faithfully-omg"}, hash)
  end

  def test_dash_with_custom_regexp
    rs.draw do
113
      get '/:artist/:song-omg', :constraints => { :song => /\d+/ }, :to => lambda { |env|
114
        resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
115 116 117 118
        [200, {}, [resp]]
      }
    end

119
    hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/123-omg'))
120 121 122 123 124 125
    assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
    assert_equal 'Not Found', get(URI('http://example.org/journey/faithfully-omg'))
  end

  def test_pre_dash
    rs.draw do
126
      get '/:artist/omg-:song', :to => lambda { |env|
127
        resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
128 129 130 131
        [200, {}, [resp]]
      }
    end

132
    hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/omg-faithfully'))
133 134 135 136 137
    assert_equal({"artist"=>"journey", "song"=>"faithfully"}, hash)
  end

  def test_pre_dash_with_custom_regexp
    rs.draw do
138
      get '/:artist/omg-:song', :constraints => { :song => /\d+/ }, :to => lambda { |env|
139
        resp = ActiveSupport::JSON.encode env[ActionDispatch::Routing::RouteSet::PARAMETERS_KEY]
140 141 142 143
        [200, {}, [resp]]
      }
    end

144
    hash = ActiveSupport::JSON.decode get(URI('http://example.org/journey/omg-123'))
145 146 147 148
    assert_equal({"artist"=>"journey", "song"=>"123"}, hash)
    assert_equal 'Not Found', get(URI('http://example.org/journey/omg-faithfully'))
  end

149
  def test_star_paths_are_greedy
150
    rs.draw do
151
      get "/*path", :to => lambda { |env|
152 153 154 155 156 157 158 159 160 161 162
        x = env["action_dispatch.request.path_parameters"][:path]
        [200, {}, [x]]
      }, :format => false
    end

    u = URI('http://example.org/foo/bar.html')
    assert_equal u.path.sub(/^\//, ''), get(u)
  end

  def test_star_paths_are_greedy_but_not_too_much
    rs.draw do
163
      get "/*path", :to => lambda { |env|
164
        x = ActiveSupport::JSON.encode env["action_dispatch.request.path_parameters"]
165 166 167 168 169 170
        [200, {}, [x]]
      }
    end

    expected = { "path" => "foo/bar", "format" => "html" }
    u = URI('http://example.org/foo/bar.html')
171
    assert_equal expected, ActiveSupport::JSON.decode(get(u))
172 173 174
  end

  def test_optional_star_paths_are_greedy
175
    rs.draw do
176
      get "/(*filters)", :to => lambda { |env|
177 178 179 180 181 182 183 184 185
        x = env["action_dispatch.request.path_parameters"][:filters]
        [200, {}, [x]]
      }, :format => false
    end

    u = URI('http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794')
    assert_equal u.path.sub(/^\//, ''), get(u)
  end

186
  def test_optional_star_paths_are_greedy_but_not_too_much
187
    rs.draw do
188
      get "/(*filters)", :to => lambda { |env|
189
        x = ActiveSupport::JSON.encode env["action_dispatch.request.path_parameters"]
190 191 192 193 194 195 196
        [200, {}, [x]]
      }
    end

    expected = { "filters" => "ne_27.065938,-80.6092/sw_25.489856,-82",
                 "format"  => "542794" }
    u = URI('http://example.org/ne_27.065938,-80.6092/sw_25.489856,-82.542794')
197
    assert_equal expected, ActiveSupport::JSON.decode(get(u))
198 199
  end

200
  def test_regexp_precidence
201
    rs.draw do
202
      get '/whois/:domain', :constraints => {
203
        :domain => /\w+\.[\w\.]+/ },
A
Aaron Patterson 已提交
204
        :to     => lambda { |env| [200, {}, %w{regexp}] }
205

206
      get '/whois/:id', :to => lambda { |env| [200, {}, %w{id}] }
207 208
    end

A
Aaron Patterson 已提交
209 210
    assert_equal 'regexp', get(URI('http://example.org/whois/example.org'))
    assert_equal 'id', get(URI('http://example.org/whois/123'))
211 212
  end

A
Aaron Patterson 已提交
213 214 215 216 217 218 219
  def test_class_and_lambda_constraints
    subdomain = Class.new {
      def matches? request
        request.subdomain.present? and request.subdomain != 'clients'
      end
    }

220
    rs.draw do
221
      get '/', :constraints => subdomain.new,
A
Aaron Patterson 已提交
222
                 :to          => lambda { |env| [200, {}, %w{default}] }
223
      get '/', :constraints => { :subdomain => 'clients' },
A
Aaron Patterson 已提交
224
                 :to          => lambda { |env| [200, {}, %w{clients}] }
A
Aaron Patterson 已提交
225 226
    end

A
Aaron Patterson 已提交
227 228
    assert_equal 'default', get(URI('http://www.example.org/'))
    assert_equal 'clients', get(URI('http://clients.example.org/'))
A
Aaron Patterson 已提交
229 230 231
  end

  def test_lambda_constraints
232
    rs.draw do
233
      get '/', :constraints => lambda { |req|
A
Aaron Patterson 已提交
234
        req.subdomain.present? and req.subdomain != "clients" },
A
Aaron Patterson 已提交
235
                 :to          => lambda { |env| [200, {}, %w{default}] }
A
Aaron Patterson 已提交
236

237
      get '/', :constraints => lambda { |req|
A
Aaron Patterson 已提交
238
        req.subdomain.present? && req.subdomain == "clients" },
A
Aaron Patterson 已提交
239
                 :to          => lambda { |env| [200, {}, %w{clients}] }
A
Aaron Patterson 已提交
240 241
    end

A
Aaron Patterson 已提交
242 243
    assert_equal 'default', get(URI('http://www.example.org/'))
    assert_equal 'clients', get(URI('http://clients.example.org/'))
A
Aaron Patterson 已提交
244 245
  end

246 247 248 249 250 251 252 253 254
  def test_empty_string_match
    rs.draw do
      get '/:username', :constraints => { :username => /[^\/]+/ },
                       :to => lambda { |e| [200, {}, ['foo']] }
    end
    assert_equal 'Not Found', get(URI('http://example.org/'))
    assert_equal 'foo', get(URI('http://example.org/hello'))
  end

255 256 257 258 259 260 261 262 263 264 265 266 267
  def test_non_greedy_glob_regexp
    params = nil
    rs.draw do
      get '/posts/:id(/*filters)', :constraints => { :filters => /.+?/ },
        :to => lambda { |e|
        params = e["action_dispatch.request.path_parameters"]
        [200, {}, ['foo']]
      }
    end
    assert_equal 'foo', get(URI('http://example.org/posts/1/foo.js'))
    assert_equal({:id=>"1", :filters=>"foo", :format=>"js"}, params)
  end

268 269
  def test_draw_with_block_arity_one_raises
    assert_raise(RuntimeError) do
270
      rs.draw { |map| map.match '/:controller(/:action(/:id))' }
271 272 273
    end
  end

A
Aaron Patterson 已提交
274
  def test_specific_controller_action_failure
275
    rs.draw do
A
Aaron Patterson 已提交
276 277 278
      mount lambda {} => "/foo"
    end

279
    assert_raises(ActionController::UrlGenerationError) do
280
      url_for(rs, :controller => "omg", :action => "lol")
A
Aaron Patterson 已提交
281 282 283
    end
  end

284
  def test_default_setup
285
    rs.draw { get '/:controller(/:action(/:id))' }
286
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
287
    assert_equal({:controller => "content", :action => 'list'},  rs.recognize_path("/content/list"))
288 289 290 291
    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"))

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

294 295
    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' })
296

297 298
    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' })
299 300 301
  end

  def test_ignores_leading_slash
302 303
    rs.clear!
    rs.draw { get '/:controller(/:action(/:id))'}
304 305 306 307
    test_default_setup
  end

  def test_route_with_colon_first
308
    rs.draw do
309 310
      get '/:controller/:action/:id', :action => 'index', :id => nil
      get ':url', :controller => 'tiny_url', :action => 'translate'
311
    end
312 313 314
  end

  def test_route_with_regexp_for_controller
315
    rs.draw do
316 317
      get ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/
      get '/:controller(/:action(/:id))'
318
    end
319

320 321
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
322 323 324 325 326
    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" })
327
  end
328

329
  def test_route_with_regexp_and_captures_for_controller
330
    rs.draw do
331
      get '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/
332 333 334
    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"))
335
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
336 337
  end

338
  def test_route_with_regexp_and_dot
339
    rs.draw do
340
      get ':controller/:action/:file',
341 342 343 344
                :controller => /admin|user/,
                :action => /upload|download/,
                :defaults => {:file => nil},
                :constraints => {:file => %r{[^/]+(\.[^/]+)?}}
345 346 347
    end
    # Without a file extension
    assert_equal '/user/download/file',
348 349 350
      url_for(rs, { :controller => "user", :action => "download", :file => "file" })

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

353 354
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
355 356 357
      url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" })

    assert_equal({:controller => "user", :action => "download", :file => "file.jpg"},
358 359
      rs.recognize_path("/user/download/file.jpg"))
  end
360

361
  def test_basic_named_route
362
    rs.draw do
363
      root :to => 'content#list', :as => 'home'
364
    end
365
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
366
  end
367

368
  def test_named_route_with_option
369
    rs.draw do
370
      get 'page/:title' => 'content#show_page', :as => 'page'
371
    end
372

373
    assert_equal("http://test.host/page/new%20stuff",
374
        setup_for_named_route.send(:page_url, :title => 'new stuff'))
375
  end
376

377
  def test_named_route_with_default
378
    rs.draw do
379
      get 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'
380
    end
381

382 383
    assert_equal("http://test.host/page/AboutRails",
        setup_for_named_route.send(:page_url, :title => "AboutRails"))
384
  end
385

386
  def test_named_route_with_path_prefix
387
    rs.draw do
388
      scope "my" do
389
        get 'page' => 'content#show_page', :as => 'page'
390
      end
391
    end
392

393
    assert_equal("http://test.host/my/page",
394
        setup_for_named_route.send(:page_url))
395
  end
396

397
  def test_named_route_with_blank_path_prefix
398
    rs.draw do
399
      scope "" do
400
        get 'page' => 'content#show_page', :as => 'page'
401
      end
402
    end
403

404
    assert_equal("http://test.host/page",
405
        setup_for_named_route.send(:page_url))
406 407
  end

408
  def test_named_route_with_nested_controller
409
    rs.draw do
410
      get 'admin/user' => 'admin/user#index', :as => "users"
411
    end
412

413
    assert_equal("http://test.host/admin/user",
414
        setup_for_named_route.send(:users_url))
415
  end
416

417
  def test_optimised_named_route_with_host
418
    rs.draw do
419
      get 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com'
420
    end
421 422 423 424 425 426 427 428 429
    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)
430
  end
431

432 433
  def setup_for_named_route(options = {})
    MockController.build(rs.url_helpers, options).new
434
  end
435

436
  def test_named_route_without_hash
437
    rs.draw do
438
      get ':controller/:action/:id', :as => 'normal'
439
    end
440
  end
441

442
  def test_named_route_root
443 444
    rs.draw do
      root :to => "hello#index"
445
    end
446 447 448
    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("/", routes.send(:root_path))
449
  end
450

B
Brian Cardarella 已提交
451 452 453 454 455 456 457 458 459
  def test_named_route_root_without_hash
    rs.draw do
      root "hello#index"
    end
    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("/", routes.send(:root_path))
  end

F
Francesco Rodriguez 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
  def test_named_route_root_with_hash
    rs.draw do
      root "hello#index", as: :index
    end

    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:index_url))
    assert_equal("/", routes.send(:index_path))
  end

  def test_root_without_path_raises_argument_error
    assert_raises ArgumentError do
      rs.draw { root nil }
    end
  end

476 477 478 479 480 481 482 483 484 485
  def test_named_route_root_with_trailing_slash
    rs.draw do
      root "hello#index"
    end

    routes = setup_for_named_route(trailing_slash: true)
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("http://test.host/?foo=bar", routes.send(:root_url, foo: :bar))
  end

486
  def test_named_route_with_regexps
487
    rs.draw do
488
      get 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',
489
        :year => /\d+/, :month => /\d+/, :day => /\d+/
490
      get ':controller/:action/:id'
491
    end
492 493 494 495 496

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

499
  def test_changing_controller
500
    rs.draw { get ':controller/:action/:id' }
501

502 503 504
    assert_equal '/admin/stuff/show/10',
        url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10},
                    {:controller => 'admin/user', :action => 'index'})
505
  end
506

507
  def test_paths_escaped
508
    rs.draw do
509 510
      get 'file/*path' => 'content#show_file', :as => 'path'
      get ':controller/:action/:id'
511
    end
512

513 514 515
    # 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"
516
    assert_equal 'hello+world/how+are+you?', results[:path]
517

518 519 520
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
521
    assert_equal 'hello world/how are you?', results[:path]
522
  end
523

524
  def test_paths_slashes_unescaped_with_ordered_parameters
525
    rs.draw do
526
      get '/file/*path' => 'content#index', :as => 'path'
527
    end
528

529
    # No / to %2F in URI, only for query params.
530
    assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world']))
531
  end
532

533
  def test_non_controllers_cannot_be_matched
534
    rs.draw do
535
      get ':controller/:action/:id'
536
    end
537
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
538
  end
539

540 541
  def test_should_list_options_diff_when_routing_constraints_dont_match
    rs.draw do
542
      get 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post'
543
    end
544
    assert_raise(ActionController::UrlGenerationError) do
545 546
      url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" })
    end
547 548 549
  end

  def test_dynamic_path_allowed
550
    rs.draw do
551
      get '*path' => 'content#show_file'
552
    end
553

554 555
    assert_equal '/pages/boo',
        url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
556
  end
557

558
  def test_dynamic_recall_paths_allowed
559
    rs.draw do
560
      get '*path' => 'content#show_file'
561 562
    end

563 564
    assert_equal '/pages/boo',
        url_for(rs, {}, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
565
  end
566

567
  def test_backwards
568
    rs.draw do
569 570
      get 'page/:id(/:action)' => 'pages#show'
      get ':controller(/:action(/:id))'
571 572
    end

573 574 575
    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' })
576 577 578
  end

  def test_route_with_fixnum_default
579
    rs.draw do
580 581
      get 'page(/:id)' => 'content#show_page', :id => 1
      get ':controller/:action/:id'
582 583
    end

584 585 586 587
    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 })
588

589
    assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page"))
590 591 592 593 594 595
    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
596
    rs.draw do
597 598
      get 'page/:id' => 'content#show_page', :id => 1
      get ':controller/:action/:id'
599 600
    end

601 602
    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"))
603

R
R.T. Lechow 已提交
604
    token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in Russian
605
    token.force_encoding(Encoding::BINARY)
606
    escaped_token = CGI::escape(token)
607

608 609
    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}"))
610
  end
611

612
  def test_action_expiry
613
    rs.draw { get ':controller(/:action(/:id))' }
614
    assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' })
615
  end
616

617
  def test_requirement_should_prevent_optional_id
618
    rs.draw do
619
      get 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'
620 621
    end

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

624
    assert_raise(ActionController::UrlGenerationError) do
625
      url_for(rs, { :controller => 'post', :action => 'show' })
626
    end
627
  end
628

629
  def test_both_requirement_and_optional
630
    rs.draw do
631
      get('test(/:year)' => 'post#show', :as => 'blog',
632
        :defaults => { :year => nil },
633
        :constraints => { :year => /\d{4}/ }
634
      )
635
      get ':controller/:action/:id'
636
    end
637

638 639
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' })
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil })
640

641
    assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url))
642
  end
643

644
  def test_set_to_nil_forgets
645
    rs.draw do
646 647
      get 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil
      get ':controller/:action/:id'
648 649
    end

650
    assert_equal '/pages/2005',
651
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 })
652
    assert_equal '/pages/2005/6',
653
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 })
654
    assert_equal '/pages/2005/6/12',
655
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 })
656

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

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

663
    assert_equal '/pages/2005',
664
      url_for(rs, { :day => nil, :month => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
665
  end
666

667
  def test_root_url_generation_with_controller_and_action
668
    rs.draw do
669
      root :to => "content#index"
670 671
    end

672 673
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
674
  end
675

676
  def test_named_root_url_generation_with_controller_and_action
677
    rs.draw do
678
       root :to => "content#index", :as => 'home'
679 680
    end

681 682
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
683

684
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
685
  end
686

687
  def test_named_route_method
688
    rs.draw do
689 690
      get 'categories' => 'content#categories', :as => 'categories'
      get ':controller(/:action(/:id))'
691 692
    end

693 694
    assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' })
    assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' })
695 696 697 698 699 700
  end

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

702
  def test_nil_defaults
703
    rs.draw do
704
      get 'journal' => 'content#list_journal',
705
        :date => nil, :user_id => nil
706
      get ':controller/:action/:id'
707
    end
708

709 710 711 712 713 714
    assert_equal '/journal', url_for(rs, {
      :controller => 'content',
      :action => 'list_journal',
      :date => nil,
      :user_id => nil
    })
715
  end
716

717
  def setup_request_method_routes_for(method)
718
    rs.draw do
V
Vipul A M 已提交
719
      match '/match' => "books##{method}", :via => method.to_sym
720
    end
721
  end
722

723
  %w(GET PATCH POST PUT DELETE).each do |request_method|
724
    define_method("test_request_method_recognized_with_#{request_method}") do
V
Vipul A M 已提交
725
      setup_request_method_routes_for(request_method.downcase)
J
Joshua Peek 已提交
726 727
      params = rs.recognize_path("/match", :method => request_method)
      assert_equal request_method.downcase, params[:action]
728 729
    end
  end
730

731
  def test_recognize_array_of_methods
732
    rs.draw do
733
      match '/match' => 'books#get_or_post', :via => [:get, :post]
734
      put '/match' => 'books#not_get_or_post'
735 736
    end

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

J
Joshua Peek 已提交
740 741
    params = rs.recognize_path("/match", :method => :put)
    assert_equal 'not_get_or_post', params[:action]
742
  end
743

744
  def test_subpath_recognized
745
    rs.draw do
746 747 748 749
      get '/books/:id/edit'    => 'subpath_books#edit'
      get '/items/:id/:action' => 'subpath_books'
      get '/posts/new/:action' => 'subpath_books'
      get '/posts/:id'         => 'subpath_books#show'
750 751
    end

752 753 754
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
755

756 757 758 759 760 761 762 763 764 765 766 767
    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
768

769
  def test_subpath_generated
770
    rs.draw do
771 772 773
      get '/books/:id/edit'    => 'subpath_books#edit'
      get '/items/:id/:action' => 'subpath_books'
      get '/posts/new/:action' => 'subpath_books'
774 775
    end

776 777 778
    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" })
779
  end
780

781 782
  def test_failed_constraints_raises_exception_with_violated_constraints
    rs.draw do
783
      get 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ }
784 785
    end

786
    assert_raise(ActionController::UrlGenerationError) do
787
      setup_for_named_route.send(:foo_with_requirement_url, "I am Against the constraints")
788 789
    end
  end
790

791
  def test_routes_changed_correctly_after_clear
792
    rs = ::ActionDispatch::Routing::RouteSet.new
793
    rs.draw do
794 795 796 797 798
      get 'ca' => 'ca#aa'
      get 'cb' => 'cb#ab'
      get 'cc' => 'cc#ac'
      get ':controller/:action/:id'
      get ':controller/:action/:id.:format'
799 800
    end

801
    hash = rs.recognize_path "/cc"
802

803 804
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
805

806
    rs.draw do
807 808 809 810
      get 'cb' => 'cb#ab'
      get 'cc' => 'cc#ac'
      get ':controller/:action/:id'
      get ':controller/:action/:id.:format'
811 812
    end

813
    hash = rs.recognize_path "/cc"
814

815 816 817 818
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
  end
end
819

820
class RouteSetTest < ActiveSupport::TestCase
821 822
  include RoutingTestHelpers

823 824 825
  def set
    @set ||= ROUTING::RouteSet.new
  end
826

827 828 829
  def request
    @request ||= ActionController::TestRequest.new
  end
830

831 832
  def default_route_set
    @default_route_set ||= begin
J
Joshua Peek 已提交
833
      set = ROUTING::RouteSet.new
834
      set.draw do
835
        get '/:controller(/:action(/:id))'
836 837 838 839 840
      end
      set
    end
  end

841
  def test_generate_extras
842
    set.draw { get ':controller/(:action(/:id))' }
843 844
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
845
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
846
  end
847

848
  def test_extra_keys
849
    set.draw { get ':controller/:action/:id' }
850
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
851
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
852
  end
853

854
  def test_generate_extras_not_first
855
    set.draw do
856 857
      get ':controller/:action/:id.:format'
      get ':controller/:action/:id'
858
    end
859 860
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
861
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
862
  end
863

864
  def test_generate_not_first
865
    set.draw do
866 867
      get ':controller/:action/:id.:format'
      get ':controller/:action/:id'
868
    end
869 870
    assert_equal "/foo/bar/15?this=hello",
        url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" })
871
  end
872

873
  def test_extra_keys_not_first
874
    set.draw do
875 876
      get ':controller/:action/:id.:format'
      get ':controller/:action/:id'
877
    end
878
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
879
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
880
  end
881

882 883
  def test_draw
    assert_equal 0, set.routes.size
884
    set.draw do
885
      get '/hello/world' => 'a#b'
886
    end
887 888
    assert_equal 1, set.routes.size
  end
889

890 891
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
892
    set.draw do
893
      get '/users/index' => 'users#index'
894
    end
895
    set.recognize_path('/users/index', :method => :get)
896 897 898
    assert_equal 1, set.routes.size
  end

899 900
  def test_named_draw
    assert_equal 0, set.routes.size
901
    set.draw do
902
      get '/hello/world' => 'a#b', :as => 'hello'
903
    end
904 905 906
    assert_equal 1, set.routes.size
    assert_equal set.routes.first, set.named_routes[:hello]
  end
907

908 909 910 911 912 913
  def test_duplicate_named_route_raises_rather_than_pick_precedence
    assert_raise ArgumentError do
      set.draw do
        get '/hello/world' => 'a#b', :as => 'hello'
        get '/hello'       => 'a#b', :as => 'hello'
      end
914
    end
915
  end
916

917
  def setup_named_route_test
918
    set.draw do
919 920 921 922
      get '/people(/:id)' => 'people#show', :as => 'show'
      get '/people' => 'people#index', :as => 'index'
      get '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi'
      get '/admin/users' => 'admin/users#index', :as => "users"
923 924
    end

925
    MockController.build(set.url_helpers).new
926
  end
927

928 929
  def test_named_route_url_method
    controller = setup_named_route_test
930

931 932
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
933

934 935
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
936

937 938 939
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
  end
940

941 942
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
943

944 945
    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')
946

947 948
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
949

950 951
    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')
952

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

956 957
    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')
958

959 960 961
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
962

963 964 965 966
  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
967

968 969 970 971
  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
972

973 974 975 976
  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
977

978 979 980 981 982
  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
983

984 985 986 987 988
  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
989

990 991 992 993 994
  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
995

996 997 998 999 1000
  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
1001

1002
  def test_draw_default_route
1003
    set.draw do
1004
      get '/:controller/:action/:id'
J
Joshua Peek 已提交
1005
    end
1006

J
Joshua Peek 已提交
1007
    assert_equal 1, set.routes.size
1008

1009 1010
    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 })
1011

J
Joshua Peek 已提交
1012 1013
    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/'))
1014
  end
1015

1016
  def test_route_with_parameter_shell
1017
    set.draw do
1018 1019
      get 'page/:id' => 'pages#show', :id => /\d+/
      get '/:controller(/:action(/:id))'
J
Joshua Peek 已提交
1020
    end
1021

J
Joshua Peek 已提交
1022 1023 1024
    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'))
1025

J
Joshua Peek 已提交
1026 1027
    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'))
1028
  end
1029

1030 1031 1032
  def test_route_constraints_on_request_object_with_anchors_are_valid
    assert_nothing_raised do
      set.draw do
1033
        get 'page/:id' => 'pages#show', :constraints => { :host => /^foo$/ }
1034 1035 1036 1037
      end
    end
  end

1038
  def test_route_constraints_with_anchor_chars_are_invalid
1039
    assert_raise ArgumentError do
1040
      set.draw do
1041
        get 'page/:id' => 'pages#show', :id => /^\d+/
1042
      end
1043
    end
1044
    assert_raise ArgumentError do
1045
      set.draw do
1046
        get 'page/:id' => 'pages#show', :id => /\A\d+/
1047 1048
      end
    end
1049
    assert_raise ArgumentError do
1050
      set.draw do
1051
        get 'page/:id' => 'pages#show', :id => /\d+$/
1052 1053
      end
    end
1054
    assert_raise ArgumentError do
1055
      set.draw do
1056
        get 'page/:id' => 'pages#show', :id => /\d+\Z/
1057 1058
      end
    end
1059
    assert_raise ArgumentError do
1060
      set.draw do
1061
        get 'page/:id' => 'pages#show', :id => /\d+\z/
1062
      end
1063 1064
    end
  end
1065

1066
  def test_route_constraints_with_options_method_condition_is_valid
1067
    assert_nothing_raised do
1068
      set.draw do
1069
        match 'valid/route' => 'pages#show', :via => :options
1070 1071 1072 1073
      end
    end
  end

1074 1075 1076 1077
  def test_route_error_with_missing_controller
    set.draw do
      get    "/people" => "missing#index"
    end
1078

1079 1080 1081 1082 1083
    assert_raise(ActionController::RoutingError) {
      set.recognize_path("/people", :method => :get)
    }
  end

1084
  def test_recognize_with_encoded_id_and_regex
1085
    set.draw do
1086
      get 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/
1087
    end
1088

1089 1090 1091 1092
    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

1093 1094 1095 1096 1097 1098
  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"
1099
      patch  "/people/:id" => "people#update"
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
      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])

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

1115
    assert_raise(ActionController::UnknownHttpMethod) {
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
      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])

1127 1128 1129 1130
    params = set.recognize_path("/people/5", :method => :patch)
    assert_equal("update", params[:action])
    assert_equal("5", params[:id])

1131 1132 1133 1134 1135 1136 1137 1138 1139
    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

1140
  def test_recognize_with_alias_in_conditions
1141
    set.draw do
1142 1143
      match "/people" => 'people#index', :as => 'people', :via => :get
      root :to => "people#index"
1144
    end
1145

J
Joshua Peek 已提交
1146 1147 1148
    params = set.recognize_path("/people", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1149

J
Joshua Peek 已提交
1150 1151 1152
    params = set.recognize_path("/", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1153
  end
1154

1155
  def test_typo_recognition
1156
    set.draw do
1157
      get 'articles/:year/:month/:day/:title' => 'articles#permalink',
1158
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
1159
    end
1160

J
Joshua Peek 已提交
1161 1162 1163 1164 1165 1166
    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])
1167
  end
1168

1169 1170
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
1171
    set.draw do
1172
      get '/profile' => 'profile#index'
1173 1174
    end

1175
    set.recognize_path("/profile") rescue nil
1176

1177 1178 1179 1180
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
1181
    set.draw do
1182 1183
      get "people/:id" => "people#show", :as => "person"
      put "people/:id" => "people#update"
1184
      patch "people/:id" => "people#update"
1185
      get "people/:id(.:format)" => "people#show"
1186 1187
    end

J
Joshua Peek 已提交
1188 1189 1190
    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1191

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

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

J
Joshua Peek 已提交
1198 1199 1200
    params = set.recognize_path("/people/5.png", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1201
    assert_equal("png", params[:format])
1202 1203 1204
  end

  def test_generate_with_default_action
1205
    set.draw do
1206 1207
      get "/people", :controller => "people", :action => "index"
      get "/people/list", :controller => "people", :action => "list"
1208 1209
    end

1210
    url = url_for(set, { :controller => "people", :action => "list" })
1211 1212
    assert_equal "/people/list", url
  end
1213

1214
  def test_root_map
1215
    set.draw { root :to => 'people#index' }
1216

J
Joshua Peek 已提交
1217 1218 1219
    params = set.recognize_path("", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1220 1221 1222
  end

  def test_namespace
1223
    set.draw do
1224

1225
      namespace 'api' do
1226
        get 'inventory' => 'products#inventory'
1227
      end
1228

1229 1230
    end

J
Joshua Peek 已提交
1231 1232 1233
    params = set.recognize_path("/api/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1234
  end
1235

1236
  def test_namespaced_root_map
1237 1238
    set.draw do
      namespace 'api' do
1239
        root :to => 'products#index'
1240 1241 1242
      end
    end

J
Joshua Peek 已提交
1243 1244 1245
    params = set.recognize_path("/api", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("index", params[:action])
1246
  end
1247

1248
  def test_namespace_with_path_prefix
1249
    set.draw do
1250
      scope :module => "api", :path => "prefix" do
1251
        get 'inventory' => 'products#inventory'
1252
      end
1253 1254
    end

J
Joshua Peek 已提交
1255 1256 1257
    params = set.recognize_path("/prefix/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1258
  end
1259

1260
  def test_namespace_with_blank_path_prefix
1261
    set.draw do
1262
      scope :module => "api", :path => "" do
1263
        get 'inventory' => 'products#inventory'
1264 1265 1266
      end
    end

J
Joshua Peek 已提交
1267 1268 1269
    params = set.recognize_path("/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1270 1271
  end

1272
  def test_generate_changes_controller_module
1273
    set.draw { get ':controller/:action/:id' }
1274
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
1275 1276 1277

    assert_equal "/foo/bar/baz/7",
        url_for(set, { :controller => "foo/bar", :action => "baz", :id => 7 }, current)
1278 1279 1280
  end

  def test_id_is_sticky_when_it_ought_to_be
1281
    set.draw do
1282
      get ':controller/:id/:action'
1283
    end
1284

1285
    url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" })
1286 1287
    assert_equal "/people/7/destroy", url
  end
1288

1289
  def test_use_static_path_when_possible
1290
    set.draw do
1291 1292
      get 'about' => "welcome#about"
      get ':controller/:action/:id'
1293 1294
    end

1295 1296 1297
    url = url_for(set, { :controller => "welcome", :action => "about" },
      { :controller => "welcome", :action => "get", :id => "7" })

1298 1299
    assert_equal "/about", url
  end
1300

1301
  def test_generate
1302
    set.draw { get ':controller/:action/:id' }
1303

1304
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1305
    assert_equal "/foo/bar/7?x=y",     url_for(set, args)
1306 1307 1308
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1309

1310
  def test_generate_with_path_prefix
1311 1312
    set.draw do
      scope "my" do
1313
        get ':controller(/:action(/:id))'
1314 1315
      end
    end
1316

1317
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1318
    assert_equal "/my/foo/bar/7?x=y", url_for(set, args)
1319 1320
  end

1321
  def test_generate_with_blank_path_prefix
1322 1323
    set.draw do
      scope "" do
1324
        get ':controller(/:action(/:id))'
1325 1326
      end
    end
1327 1328

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

1332
  def test_named_routes_are_never_relative_to_modules
1333
    set.draw do
1334 1335 1336
      get "/connection/manage(/:action)" => 'connection/manage#index'
      get "/connection/connection" => "connection/connection#index"
      get '/connection' => 'connection#index', :as => 'family_connection'
1337
    end
1338

1339
    url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' })
1340 1341
    assert_equal "/connection/connection", url

1342
    url = url_for(set, { :use_route => :family_connection, :controller => "connection" }, { :controller => 'connection/manage' })
1343 1344 1345 1346
    assert_equal "/connection", url
  end

  def test_action_left_off_when_id_is_recalled
1347
    set.draw do
1348
      get ':controller(/:action(/:id))'
1349
    end
1350
    assert_equal '/books', url_for(set,
1351 1352
      {:controller => 'books', :action => 'index'},
      {:controller => 'books', :action => 'show', :id => '10'}
1353 1354
    )
  end
1355

1356
  def test_query_params_will_be_shown_when_recalled
1357
    set.draw do
1358 1359
      get 'show_weblog/:parameter' => 'weblog#show'
      get ':controller(/:action(/:id))'
1360
    end
1361
    assert_equal '/weblog/edit?parameter=1', url_for(set,
1362
      {:action => 'edit', :parameter => 1},
1363
      {:controller => 'weblog', :action => 'show', :parameter => 1}
1364 1365
    )
  end
1366

1367
  def test_format_is_not_inherit
1368
    set.draw do
1369
      get '/posts(.:format)' => 'posts#index'
1370 1371
    end

1372
    assert_equal '/posts', url_for(set,
1373 1374 1375 1376
      {:controller => 'posts'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )

1377
    assert_equal '/posts.xml', url_for(set,
1378 1379 1380 1381 1382
      {:controller => 'posts', :format => 'xml'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )
  end

1383
  def test_expiry_determination_should_consider_values_with_to_param
1384
    set.draw { get 'projects/:project_id/:controller/:action' }
1385 1386 1387
    assert_equal '/projects/1/weblog/show', url_for(set,
      { :action => 'show', :project_id => 1 },
      { :controller => 'weblog', :action => 'show', :project_id => '1' })
1388
  end
1389

1390
  def test_named_route_in_nested_resource
1391 1392
    set.draw do
      resources :projects do
1393
        member do
1394
          get 'milestones' => 'milestones#index', :as => 'milestones'
1395
        end
1396 1397
      end
    end
1398

J
Joshua Peek 已提交
1399 1400 1401
    params = set.recognize_path("/projects/1/milestones", :method => :get)
    assert_equal("milestones", params[:controller])
    assert_equal("index", params[:action])
1402
  end
1403

1404 1405
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
1406 1407
      set.draw do
        namespace :admin do
1408
          root :to => "home#index"
1409 1410 1411
        end
      end
    end
1412
  end
1413

1414 1415
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
1416 1417
      set.draw do
        namespace 'admin' do
1418
          root :to => "home#index"
1419 1420 1421
        end
      end
    end
1422
  end
1423

1424
  def test_route_constraints_with_unsupported_regexp_options_must_error
1425
    assert_raise ArgumentError do
1426
      set.draw do
1427
        get 'page/:name' => 'pages#show',
1428
          :constraints => { :name => /(david|jamis)/m }
1429
      end
1430
    end
1431
  end
1432

1433
  def test_route_constraints_with_supported_options_must_not_error
1434
    assert_nothing_raised do
1435
      set.draw do
1436
        get 'page/:name' => 'pages#show',
1437
          :constraints => { :name => /(david|jamis)/i }
1438 1439
      end
    end
1440
    assert_nothing_raised do
1441
      set.draw do
1442
        get 'page/:name' => 'pages#show',
1443
          :constraints => { :name => / # Desperately overcommented regexp
1444 1445 1446 1447
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
1448
                                      )/x }
1449 1450
      end
    end
1451
  end
1452

1453 1454 1455
  def test_route_with_subdomain_and_constraints_must_receive_params
    name_param = nil
    set.draw do
1456
      get 'page/:name' => 'pages#show', :constraints => lambda {|request|
1457 1458 1459 1460 1461 1462 1463 1464
        name_param = request.params[:name]
        return true
      }
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'mypage'},
      set.recognize_path('http://subdomain.example.org/page/mypage'))
    assert_equal(name_param, 'mypage')
  end
1465

1466
  def test_route_requirement_recognize_with_ignore_case
1467
    set.draw do
1468
      get 'page/:name' => 'pages#show',
1469
        :constraints => {:name => /(david|jamis)/i}
1470 1471
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1472
    assert_raise ActionController::RoutingError do
1473
      set.recognize_path('/page/davidjamis')
1474
    end
1475 1476
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1477

1478
  def test_route_requirement_generate_with_ignore_case
1479
    set.draw do
1480
      get 'page/:name' => 'pages#show',
1481
        :constraints => {:name => /(david|jamis)/i}
1482
    end
1483

1484
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' })
J
Jeremy Kemper 已提交
1485
    assert_equal "/page/david", url
1486
    assert_raise(ActionController::UrlGenerationError) do
1487
      url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' })
J
Jeremy Kemper 已提交
1488
    end
1489
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
J
Jeremy Kemper 已提交
1490
    assert_equal "/page/JAMIS", url
1491
  end
J
Jeremy Kemper 已提交
1492

1493
  def test_route_requirement_recognize_with_extended_syntax
1494
    set.draw do
1495
      get 'page/:name' => 'pages#show',
1496
        :constraints => {:name => / # Desperately overcommented regexp
1497 1498 1499 1500 1501 1502 1503 1504
                                    ( #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'))
1505
    assert_raise ActionController::RoutingError do
1506 1507
      set.recognize_path('/page/david #The Creator')
    end
1508
    assert_raise ActionController::RoutingError do
1509
      set.recognize_path('/page/David')
1510 1511
    end
  end
1512

1513
  def test_route_requirement_with_xi_modifiers
1514
    set.draw do
1515
      get 'page/:name' => 'pages#show',
1516
        :constraints => {:name => / # Desperately overcommented regexp
1517 1518 1519 1520 1521
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1522
    end
1523

1524 1525
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'},
        set.recognize_path('/page/JAMIS'))
1526

1527 1528
    assert_equal "/page/JAMIS",
        url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
1529
  end
1530 1531

  def test_routes_with_symbols
1532
    set.draw do
1533 1534
      get 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol
      get 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named
1535 1536 1537 1538 1539
    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

1540
  def test_regexp_chunk_should_add_question_mark_for_optionals
1541
    set.draw do
1542 1543
      get '/' => 'foo#index'
      get '/hello' => 'bar#index'
J
Joshua Peek 已提交
1544
    end
1545

1546 1547
    assert_equal '/',      url_for(set, { :controller => 'foo' })
    assert_equal '/hello', url_for(set, { :controller => 'bar' })
1548

J
Joshua Peek 已提交
1549 1550
    assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/'))
    assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello'))
1551 1552 1553
  end

  def test_assign_route_options_with_anchor_chars
1554
    set.draw do
1555
      get '/cars/:action/:person/:car/', :controller => 'cars'
J
Joshua Peek 已提交
1556
    end
1557

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

J
Joshua Peek 已提交
1560
    assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2'))
1561 1562 1563
  end

  def test_segmentation_of_dot_path
1564
    set.draw do
1565
      get '/books/:action.rss', :controller => 'books'
J
Joshua Peek 已提交
1566
    end
1567

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

J
Joshua Peek 已提交
1570
    assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss'))
1571 1572 1573
  end

  def test_segmentation_of_dynamic_dot_path
1574
    set.draw do
1575
      get '/books(/:action(.:format))', :controller => 'books'
J
Joshua Peek 已提交
1576
    end
1577

1578 1579 1580 1581
    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' })
1582

J
Joshua Peek 已提交
1583 1584
    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'))
1585
    assert_equal({:controller => "books", :action => "list"},  set.recognize_path('/books/list'))
J
Joshua Peek 已提交
1586
    assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
1587 1588 1589
  end

  def test_slashes_are_implied
1590
    @set = nil
1591
    set.draw { get("/:controller(/:action(/:id))") }
1592

1593 1594 1595
    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' })
1596

1597 1598
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content'))
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index'))
1599
    assert_equal({:controller => "content", :action => "list"},  set.recognize_path('/content/list'))
1600
    assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1'))
1601 1602 1603
  end

  def test_default_route_recognition
J
Joshua Peek 已提交
1604 1605 1606
    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/')
1607 1608

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

    expected.delete :id
J
Joshua Peek 已提交
1612 1613
    assert_equal expected, default_route_set.recognize_path('/pages/show')
    assert_equal expected, default_route_set.recognize_path('/pages/show/')
1614 1615

    expected[:action] = 'index'
J
Joshua Peek 已提交
1616 1617
    assert_equal expected, default_route_set.recognize_path('/pages/')
    assert_equal expected, default_route_set.recognize_path('/pages')
1618 1619

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
J
Joshua Peek 已提交
1620
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
1621 1622 1623
  end

  def test_default_route_should_omit_default_action
1624
    assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' })
1625 1626 1627
  end

  def test_default_route_should_include_default_action_when_id_present
1628
    assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' })
1629 1630 1631
  end

  def test_default_route_should_work_with_action_but_no_id
1632
    assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' })
1633 1634 1635
  end

  def test_default_route_should_uri_escape_pluses
J
Joshua Peek 已提交
1636 1637
    expected = { :controller => 'pages', :action => 'show', :id => 'hello world' }
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world')
1638
    assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected)
1639 1640

    expected[:id] = 'hello+world'
J
Joshua Peek 已提交
1641 1642
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world')
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld')
1643
    assert_equal '/pages/show/hello+world', url_for(default_route_set, expected)
1644 1645 1646
  end

  def test_build_empty_query_string
1647
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' })
1648 1649 1650
  end

  def test_build_query_string_with_nil_value
1651
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil })
1652 1653 1654
  end

  def test_simple_build_query_string
1655
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' })
1656 1657 1658
  end

  def test_convert_ints_build_query_string
1659
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 })
1660 1661 1662
  end

  def test_escape_spaces_build_query_string
1663
    assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' })
1664 1665 1666
  end

  def test_expand_array_build_query_string
1667
    assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] })
1668 1669 1670
  end

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

1674
  def test_generate_with_default_params
1675
    set.draw do
1676 1677 1678
      get 'dummy/page/:page' => 'dummy#show'
      get 'dummy/dots/page.:page' => 'dummy#dots'
      get 'ibocorp(/:page)' => 'ibocorp#show',
1679 1680
                             :constraints => { :page => /\d+/ },
                             :defaults => { :page => 1 }
1681

1682
      get ':controller/:action/:id'
1683 1684
    end

1685
    assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 })
1686 1687
  end

1688
  def test_generate_with_optional_params_recalls_last_request
1689
    set.draw do
1690
      get "blog/", :controller => "blog", :action => "index"
1691

1692
      get "blog(/:year(/:month(/:day)))",
1693 1694 1695 1696
            :controller => "blog",
            :action => "show_date",
            :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ },
            :day => nil, :month => nil
1697

1698 1699 1700
      get "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/
      get "blog/:controller/:action(/:id)"
      get "*anything", :controller => "blog", :action => "unknown_request"
1701 1702 1703 1704
    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"))
1705 1706
    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"))
1707 1708 1709
    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"))
1710 1711
    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"))
1712 1713 1714

    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)
1715 1716 1717 1718 1719
    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))
1720 1721
  end

J
Joshua Peek 已提交
1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
  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
1732
end
1733

1734
class RackMountIntegrationTests < ActiveSupport::TestCase
1735 1736
  include RoutingTestHelpers

1737 1738
  Model = Struct.new(:to_param)

1739 1740
  Mapping = lambda {
    namespace :admin do
1741
      resources :users, :posts
1742 1743
    end

1744
    namespace 'api' do
1745
      root :to => 'users#index'
1746 1747
    end

1748
    get '/blog(/:year(/:month(/:day)))' => 'posts#show_date',
1749
      :constraints => {
1750 1751 1752 1753 1754 1755
        :year => /(19|20)\d\d/,
        :month => /[01]?\d/,
        :day => /[0-3]?\d/
      },
      :day => nil,
      :month => nil
1756

1757
    get 'archive/:year', :controller => 'archive', :action => 'index',
1758
      :defaults => { :year => nil },
1759 1760
      :constraints => { :year => /\d{4}/ },
      :as => "blog"
1761

1762
    resources :people
1763
    get 'legacy/people' => "people#index", :legacy => "true"
1764

1765 1766
    get 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol
    get 'id_default(/:id)' => "foo#id_default", :id => 1
1767
    match 'get_or_post' => "foo#get_or_post", :via => [:get, :post]
1768 1769 1770
    get 'optional/:optional' => "posts#index"
    get 'projects/:project_id' => "project#index", :as => "project"
    get 'clients' => "projects#index"
1771

1772 1773
    get 'ignorecase/geocode/:postalcode' => 'geocode#show', :postalcode => /hx\d\d-\d[a-z]{2}/i
    get 'extended/geocode/:postalcode' => 'geocode#show',:constraints => {
1774 1775 1776 1777
                  :postalcode => /# Postcode format
                                  \d{5} #Prefix
                                  (-\d{4})? #Suffix
                                  /x
1778
                  }, :as => "geocode"
1779

1780
    get 'news(.:format)' => "news#index"
1781

1782 1783 1784 1785 1786
    get 'comment/:id(/:action)' => "comments#show"
    get 'ws/:controller(/:action(/:id))', :ws => true
    get 'account(/:action)' => "account#subscription"
    get 'pages/:page_id/:controller(/:action(/:id))'
    get ':controller/ping', :action => 'ping'
1787
    get 'こんにちは/世界', :controller => 'news', :action => 'index'
1788
    match ':controller(/:action(/:id))(.:format)', :via => :all
1789
    root :to => "news#index"
1790 1791 1792
  }

  def setup
1793
    @routes = ActionDispatch::Routing::RouteSet.new
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
    @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))

1812 1813
    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))
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832
    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'))
1833
    assert_equal({:controller => 'foo', :action => 'id_default', :id => 1 }, @routes.recognize_path('/id_default'))
1834 1835
    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))
1836 1837
    assert_raise(ActionController::RoutingError) { @routes.recognize_path('/get_or_post', :method => :put) }
    assert_raise(ActionController::RoutingError) { @routes.recognize_path('/get_or_post', :method => :delete) }
1838 1839

    assert_equal({:controller => 'posts', :action => 'index', :optional => 'bar'}, @routes.recognize_path('/optional/bar'))
1840
    assert_raise(ActionController::RoutingError) { @routes.recognize_path('/optional') }
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

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

1866
    assert_equal({:controller => 'news', :action => 'index' }, @routes.recognize_path('/', :method => :get))
1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903
    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

1904 1905 1906 1907
  def test_unicode_path
    assert_equal({:controller => 'news', :action => 'index'}, @routes.recognize_path(URI.parser.escape('こんにちは/世界'), :method => :get))
  end

1908 1909 1910 1911
  def test_downcased_unicode_path
    assert_equal({:controller => 'news', :action => 'index'}, @routes.recognize_path(URI.parser.escape('こんにちは/世界').downcase, :method => :get))
  end

1912 1913 1914 1915 1916 1917 1918 1919
  private
    def sort_extras!(extras)
      if extras.length == 2
        extras[1].sort! { |a, b| a.to_s <=> b.to_s }
      end
      extras
    end
end