routing_test.rb 67.8 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
    @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}

A
Aaron Patterson 已提交
93
    @rs.call(params)[2].join
94
  end
J
Joshua Peek 已提交
95

96 97 98 99
  def test_regexp_precidence
    @rs.draw do
      match '/whois/:domain', :constraints => {
        :domain => /\w+\.[\w\.]+/ },
A
Aaron Patterson 已提交
100
        :to     => lambda { |env| [200, {}, %w{regexp}] }
101

A
Aaron Patterson 已提交
102
      match '/whois/:id', :to => lambda { |env| [200, {}, %w{id}] }
103 104
    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
  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,
A
Aaron Patterson 已提交
118
                 :to          => lambda { |env| [200, {}, %w{default}] }
A
Aaron Patterson 已提交
119
      match '/', :constraints => { :subdomain => 'clients' },
A
Aaron Patterson 已提交
120
                 :to          => lambda { |env| [200, {}, %w{clients}] }
A
Aaron Patterson 已提交
121 122
    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
  end

  def test_lambda_constraints
    @rs.draw do
      match '/', :constraints => lambda { |req|
        req.subdomain.present? and req.subdomain != "clients" },
A
Aaron Patterson 已提交
131
                 :to          => lambda { |env| [200, {}, %w{default}] }
A
Aaron Patterson 已提交
132 133 134

      match '/', :constraints => lambda { |req|
        req.subdomain.present? && req.subdomain == "clients" },
A
Aaron Patterson 已提交
135
                 :to          => lambda { |env| [200, {}, %w{clients}] }
A
Aaron Patterson 已提交
136 137
    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 148 149 150
  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

151 152 153 154 155 156 157 158 159 160 161 162 163
  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

164 165 166 167 168 169
  def test_draw_with_block_arity_one_raises
    assert_raise(RuntimeError) do
      @rs.draw { |map| map.match '/:controller(/:action(/:id))' }
    end
  end

170
  def test_default_setup
171
    @rs.draw { match '/:controller(/:action(/:id))' }
172
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
173
    assert_equal({:controller => "content", :action => 'list'},  rs.recognize_path("/content/list"))
174 175 176 177
    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"))

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

180 181
    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' })
182

183 184
    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' })
185 186 187 188
  end

  def test_ignores_leading_slash
    @rs.clear!
189
    @rs.draw { match '/:controller(/:action(/:id))'}
190 191 192 193 194
    test_default_setup
  end

  def test_time_recognition
    # We create many routes to make situation more realistic
195
    @rs = ::ActionDispatch::Routing::RouteSet.new
196
    @rs.draw {
197
      root :to => "search#new", :as => "frontpage"
198 199 200 201 202
      resources :videos do
        resources :comments
        resource  :file,      :controller => 'video_file'
        resource  :share,     :controller => 'video_shares'
        resource  :abuse,     :controller => 'video_abuses'
203
      end
204 205 206
      resources :abuses, :controller => 'video_abuses'
      resources :video_uploads
      resources :video_visits
207

208 209 210
      resources :users do
        resource  :settings
        resources :videos
211
      end
212 213
      resources :channels do
        resources :videos, :controller => 'channel_videos'
214
      end
215 216 217 218 219
      resource  :session
      resource  :lost_password
      match 'search' => 'search#index', :as => 'search'
      resources :pages
      match ':controller/:action/:id'
220 221
    }
  end
222

223
  def test_route_with_colon_first
224 225 226
    rs.draw do
      match '/:controller/:action/:id', :action => 'index', :id => nil
      match ':url', :controller => 'tiny_url', :action => 'translate'
227
    end
228 229 230
  end

  def test_route_with_regexp_for_controller
231
    rs.draw do
232 233
      match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/
      match '/:controller(/:action(/:id))'
234
    end
235

236 237
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
238 239 240 241 242
    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" })
243
  end
244

245
  def test_route_with_regexp_and_captures_for_controller
246
    rs.draw do
247
      match '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/
248 249 250
    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"))
251
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
252 253
  end

254
  def test_route_with_regexp_and_dot
255 256 257 258 259 260
    rs.draw do
      match ':controller/:action/:file',
                :controller => /admin|user/,
                :action => /upload|download/,
                :defaults => {:file => nil},
                :constraints => {:file => %r{[^/]+(\.[^/]+)?}}
261 262 263
    end
    # Without a file extension
    assert_equal '/user/download/file',
264 265 266
      url_for(rs, { :controller => "user", :action => "download", :file => "file" })

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

269 270
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
271 272 273
      url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" })

    assert_equal({:controller => "user", :action => "download", :file => "file.jpg"},
274 275
      rs.recognize_path("/user/download/file.jpg"))
  end
276

277
  def test_basic_named_route
278
    rs.draw do
279
      root :to => 'content#list', :as => 'home'
280
    end
281
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
282
  end
283

284
  def test_named_route_with_option
285 286
    rs.draw do
      match 'page/:title' => 'content#show_page', :as => 'page'
287
    end
288

289
    assert_equal("http://test.host/page/new%20stuff",
290
        setup_for_named_route.send(:page_url, :title => 'new stuff'))
291
  end
292

293
  def test_named_route_with_default
294 295
    rs.draw do
      match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'
296
    end
297

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

302
  def test_named_route_with_path_prefix
303
    rs.draw do
304 305 306
      scope "my" do
        match 'page' => 'content#show_page', :as => 'page'
      end
307
    end
308

309
    assert_equal("http://test.host/my/page",
310
        setup_for_named_route.send(:page_url))
311
  end
312

313
  def test_named_route_with_blank_path_prefix
314
    rs.draw do
315 316 317
      scope "" do
        match 'page' => 'content#show_page', :as => 'page'
      end
318
    end
319

320
    assert_equal("http://test.host/page",
321
        setup_for_named_route.send(:page_url))
322 323
  end

324
  def test_named_route_with_nested_controller
325
    rs.draw do
326
      match 'admin/user' => 'admin/user#index', :as => "users"
327
    end
328

329
    assert_equal("http://test.host/admin/user",
330
        setup_for_named_route.send(:users_url))
331
  end
332

333
  def test_optimised_named_route_with_host
334
    rs.draw do
335
      match 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com'
336
    end
337 338 339 340 341 342 343 344 345
    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)
346
  end
347

348
  def setup_for_named_route
349
    MockController.build(rs.url_helpers).new
350
  end
351

352
  def test_named_route_without_hash
353 354
    rs.draw do
      match ':controller/:action/:id', :as => 'normal'
355
    end
356
  end
357

358
  def test_named_route_root
359 360
    rs.draw do
      root :to => "hello#index"
361
    end
362 363 364
    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("/", routes.send(:root_path))
365
  end
366

367
  def test_named_route_with_regexps
368 369
    rs.draw do
      match 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',
370
        :year => /\d+/, :month => /\d+/, :day => /\d+/
371
      match ':controller/:action/:id'
372
    end
373 374 375 376 377

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

380
  def test_changing_controller
381
    @rs.draw { match ':controller/:action/:id' }
382

383 384 385
    assert_equal '/admin/stuff/show/10',
        url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10},
                    {:controller => 'admin/user', :action => 'index'})
386
  end
387

388
  def test_paths_escaped
389 390 391
    rs.draw do
      match 'file/*path' => 'content#show_file', :as => 'path'
      match ':controller/:action/:id'
392
    end
393

394 395 396
    # 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"
397
    assert_equal 'hello+world/how+are+you?', results[:path]
398

399 400 401
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
402
    assert_equal 'hello world/how are you?', results[:path]
403
  end
404

405
  def test_paths_slashes_unescaped_with_ordered_parameters
406 407
    rs.draw do
      match '/file/*path' => 'content#index', :as => 'path'
408
    end
409

410
    # No / to %2F in URI, only for query params.
411
    assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world']))
412
  end
413

414
  def test_non_controllers_cannot_be_matched
415 416
    rs.draw do
      match ':controller/:action/:id'
417
    end
418
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
419
  end
420

421 422
  def test_should_list_options_diff_when_routing_constraints_dont_match
    rs.draw do
423
      match 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post'
424
    end
425 426 427
    assert_raise(ActionController::RoutingError) do
      url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" })
    end
428 429 430
  end

  def test_dynamic_path_allowed
431 432
    rs.draw do
      match '*path' => 'content#show_file'
433
    end
434

435 436
    assert_equal '/pages/boo',
        url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
437
  end
438

439
  def test_dynamic_recall_paths_allowed
440 441
    rs.draw do
      match '*path' => 'content#show_file'
442 443
    end

444 445
    assert_equal '/pages/boo',
        url_for(rs, {}, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
446
  end
447

448
  def test_backwards
449
    rs.draw do
450 451
      match 'page/:id(/:action)' => 'pages#show'
      match ':controller(/:action(/:id))'
452 453
    end

454 455 456
    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' })
457 458 459
  end

  def test_route_with_fixnum_default
460
    rs.draw do
461
      match 'page(/:id)' => 'content#show_page', :id => 1
462
      match ':controller/:action/:id'
463 464
    end

465 466 467 468
    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 })
469

470
    assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page"))
471 472 473 474 475 476
    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
477 478 479
    rs.draw do
      match 'page/:id' => 'content#show_page', :id => 1
      match ':controller/:action/:id'
480 481
    end

482 483
    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"))
484

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

489 490
    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}"))
491
  end
492

493
  def test_action_expiry
494
    @rs.draw { match ':controller(/:action(/:id))' }
495
    assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' })
496
  end
497

498
  def test_requirement_should_prevent_optional_id
499 500
    rs.draw do
      match 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'
501 502
    end

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

505
    assert_raise ActionController::RoutingError do
506
      url_for(rs, { :controller => 'post', :action => 'show' })
507
    end
508
  end
509

510
  def test_both_requirement_and_optional
511
    rs.draw do
512
      match('test(/:year)' => 'post#show', :as => 'blog',
513
        :defaults => { :year => nil },
514
        :constraints => { :year => /\d{4}/ }
515
      )
516
      match ':controller/:action/:id'
517
    end
518

519 520
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' })
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil })
521

522
    assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url))
523
  end
524

525
  def test_set_to_nil_forgets
526
    rs.draw do
527
      match 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil
528
      match ':controller/:action/:id'
529 530
    end

531
    assert_equal '/pages/2005',
532
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 })
533
    assert_equal '/pages/2005/6',
534
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 })
535
    assert_equal '/pages/2005/6/12',
536
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 })
537

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

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

544
    assert_equal '/pages/2005',
545
      url_for(rs, { :day => nil, :month => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
546
  end
547

548
  def test_root_url_generation_with_controller_and_action
549
    rs.draw do
550
      root :to => "content#index"
551 552
    end

553 554
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
555
  end
556

557
  def test_named_root_url_generation_with_controller_and_action
558
    rs.draw do
559
       root :to => "content#index", :as => 'home'
560 561
    end

562 563
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
564

565
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
566
  end
567

568
  def test_named_route_method
569 570
    rs.draw do
      match 'categories' => 'content#categories', :as => 'categories'
571
      match ':controller(/:action(/:id))'
572 573
    end

574 575
    assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' })
    assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' })
576 577 578 579 580 581
  end

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

583
  def test_nil_defaults
584 585
    rs.draw do
      match 'journal' => 'content#list_journal',
586
        :date => nil, :user_id => nil
587
      match ':controller/:action/:id'
588
    end
589

590 591 592 593 594 595
    assert_equal '/journal', url_for(rs, {
      :controller => 'content',
      :action => 'list_journal',
      :date => nil,
      :user_id => nil
    })
596
  end
597

598
  def setup_request_method_routes_for(method)
599
    rs.draw do
600 601 602 603
      match '/match' => 'books#get', :via => :get
      match '/match' => 'books#post', :via => :post
      match '/match' => 'books#put', :via => :put
      match '/match' => 'books#delete', :via => :delete
604
    end
605
  end
606

607 608
  %w(GET POST PUT DELETE).each do |request_method|
    define_method("test_request_method_recognized_with_#{request_method}") do
609
      setup_request_method_routes_for(request_method)
J
Joshua Peek 已提交
610 611
      params = rs.recognize_path("/match", :method => request_method)
      assert_equal request_method.downcase, params[:action]
612 613
    end
  end
614

615
  def test_recognize_array_of_methods
616
    rs.draw do
617
      match '/match' => 'books#get_or_post', :via => [:get, :post]
618
      match '/match' => 'books#not_get_or_post'
619 620
    end

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

J
Joshua Peek 已提交
624 625
    params = rs.recognize_path("/match", :method => :put)
    assert_equal 'not_get_or_post', params[:action]
626
  end
627

628
  def test_subpath_recognized
629 630 631 632 633
    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'
634 635
    end

636 637 638
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
639

640 641 642 643 644 645 646 647 648 649 650 651
    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
652

653
  def test_subpath_generated
654 655 656 657
    rs.draw do
      match '/books/:id/edit'    => 'subpath_books#edit'
      match '/items/:id/:action' => 'subpath_books'
      match '/posts/new/:action' => 'subpath_books'
658 659
    end

660 661 662
    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" })
663
  end
664

665 666
  def test_failed_constraints_raises_exception_with_violated_constraints
    rs.draw do
667
      match 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ }
668 669
    end

670
    assert_raise(ActionController::RoutingError) do
671
      setup_for_named_route.send(:foo_with_requirement_url, "I am Against the constraints")
672 673
    end
  end
674

675
  def test_routes_changed_correctly_after_clear
676
    rs = ::ActionDispatch::Routing::RouteSet.new
677 678 679 680 681 682
    rs.draw do
      match 'ca' => 'ca#aa'
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
683 684
    end

685
    hash = rs.recognize_path "/cc"
686

687 688
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
689

690 691 692 693 694
    rs.draw do
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
695 696
    end

697
    hash = rs.recognize_path "/cc"
698

699 700 701 702
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
  end
end
703

704
class RouteSetTest < ActiveSupport::TestCase
705 706
  include RoutingTestHelpers

707 708 709
  def set
    @set ||= ROUTING::RouteSet.new
  end
710

711 712 713
  def request
    @request ||= ActionController::TestRequest.new
  end
714

715 716
  def default_route_set
    @default_route_set ||= begin
J
Joshua Peek 已提交
717
      set = ROUTING::RouteSet.new
718
      set.draw do
719
        match '/:controller(/:action(/:id))'
720 721 722 723 724
      end
      set
    end
  end

725
  def test_generate_extras
726
    set.draw { match ':controller/(:action(/:id))' }
727 728
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
729
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
730
  end
731

732
  def test_extra_keys
733
    set.draw { match ':controller/:action/:id' }
734
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
735
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
736
  end
737

738
  def test_generate_extras_not_first
739 740 741
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
742
    end
743 744
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
745
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
746
  end
747

748
  def test_generate_not_first
749 750 751
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
752
    end
753 754
    assert_equal "/foo/bar/15?this=hello",
        url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" })
755
  end
756

757
  def test_extra_keys_not_first
758 759 760
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
761
    end
762
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
763
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
764
  end
765

766 767
  def test_draw
    assert_equal 0, set.routes.size
768 769
    set.draw do
      match '/hello/world' => 'a#b'
770
    end
771 772
    assert_equal 1, set.routes.size
  end
773

774 775
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
776 777
    set.draw do
      match '/users/index' => 'users#index'
778
    end
779
    set.recognize_path('/users/index', :method => :get)
780 781 782
    assert_equal 1, set.routes.size
  end

783 784
  def test_named_draw
    assert_equal 0, set.routes.size
785 786
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
787
    end
788 789 790
    assert_equal 1, set.routes.size
    assert_equal set.routes.first, set.named_routes[:hello]
  end
791

792
  def test_earlier_named_routes_take_precedence
793 794 795
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
      match '/hello'       => 'a#b', :as => 'hello'
796
    end
797
    assert_equal set.routes.first, set.named_routes[:hello]
798
  end
799

800
  def setup_named_route_test
801
    set.draw do
802 803 804
      match '/people(/:id)' => 'people#show', :as => 'show'
      match '/people' => 'people#index', :as => 'index'
      match '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi'
805
      match '/admin/users' => 'admin/users#index', :as => "users"
806 807
    end

808
    MockController.build(set.url_helpers).new
809
  end
810

811 812 813 814
  def test_named_route_hash_access_method
    controller = setup_named_route_test

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

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

    assert_equal(
823
      { :controller => 'people', :action => 'show', :id => 5, :use_route => "show", :only_path => true },
824 825
      controller.send(:hash_for_show_path, :id => 5)
    )
826 827
  end

828 829
  def test_named_route_url_method
    controller = setup_named_route_test
830

831 832
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
833

834 835
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
836

837 838
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
839
    assert_equal '/admin/users', url_for(set, controller.send(:hash_for_users_url), { :controller => 'users', :action => 'index' })
840
  end
841

842 843
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
844

845 846
    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')
847

848 849
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
850

851 852
    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')
853

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

857 858
    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')
859

860 861 862
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
863

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

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

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

879 880 881 882 883
  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
884

885 886 887 888 889
  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
890

891 892 893 894 895
  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
896

897 898 899 900 901
  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
902

903
  def test_draw_default_route
904 905
    set.draw do
      match '/:controller/:action/:id'
J
Joshua Peek 已提交
906
    end
907

J
Joshua Peek 已提交
908
    assert_equal 1, set.routes.size
909

910 911
    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 })
912

J
Joshua Peek 已提交
913 914
    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/'))
915
  end
916

917
  def test_route_with_parameter_shell
918 919
    set.draw do
      match 'page/:id' => 'pages#show', :id => /\d+/
920
      match '/:controller(/:action(/:id))'
J
Joshua Peek 已提交
921
    end
922

J
Joshua Peek 已提交
923 924 925
    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'))
926

J
Joshua Peek 已提交
927 928
    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'))
929
  end
930

931 932 933 934 935 936 937 938
  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

939
  def test_route_constraints_with_anchor_chars_are_invalid
940
    assert_raise ArgumentError do
941 942
      set.draw do
        match 'page/:id' => 'pages#show', :id => /^\d+/
943
      end
944
    end
945
    assert_raise ArgumentError do
946 947
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\A\d+/
948 949
      end
    end
950
    assert_raise ArgumentError do
951 952
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+$/
953 954
      end
    end
955
    assert_raise ArgumentError do
956 957
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\Z/
958 959
      end
    end
960
    assert_raise ArgumentError do
961 962
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\z/
963
      end
964 965
    end
  end
966

967
  def test_route_constraints_with_options_method_condition_is_valid
968
    assert_nothing_raised do
969
      set.draw do
970
        match 'valid/route' => 'pages#show', :via => :options
971 972 973 974
      end
    end
  end

975
  def test_recognize_with_encoded_id_and_regex
976 977
    set.draw do
      match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/
978
    end
979

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

984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001
  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])

1002
    assert_raise(ActionController::UnknownHttpMethod) {
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
      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

1023
  def test_recognize_with_alias_in_conditions
1024
    set.draw do
1025 1026
      match "/people" => 'people#index', :as => 'people', :via => :get
      root :to => "people#index"
1027
    end
1028

J
Joshua Peek 已提交
1029 1030 1031
    params = set.recognize_path("/people", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1032

J
Joshua Peek 已提交
1033 1034 1035
    params = set.recognize_path("/", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1036
  end
1037

1038
  def test_typo_recognition
1039 1040
    set.draw do
      match 'articles/:year/:month/:day/:title' => 'articles#permalink',
1041
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
1042
    end
1043

J
Joshua Peek 已提交
1044 1045 1046 1047 1048 1049
    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])
1050
  end
1051

1052 1053
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
1054
    set.draw do
1055
      match '/profile' => 'profile#index'
1056 1057
    end

1058
    set.recognize_path("/profile") rescue nil
1059

1060 1061 1062 1063
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
1064
    set.draw do
1065 1066
      get "people/:id" => "people#show", :as => "person"
      put "people/:id" => "people#update"
1067
      get "people/:id(.:format)" => "people#show"
1068 1069
    end

J
Joshua Peek 已提交
1070 1071 1072
    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1073

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

J
Joshua Peek 已提交
1077 1078 1079
    params = set.recognize_path("/people/5.png", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1080
    assert_equal("png", params[:format])
1081 1082 1083
  end

  def test_generate_with_default_action
1084
    set.draw do
1085
      match "/people", :controller => "people", :action => "index"
1086
      match "/people/list", :controller => "people", :action => "list"
1087 1088
    end

1089
    url = url_for(set, { :controller => "people", :action => "list" })
1090 1091
    assert_equal "/people/list", url
  end
1092

1093
  def test_root_map
1094
    set.draw { root :to => 'people#index' }
1095

J
Joshua Peek 已提交
1096 1097 1098
    params = set.recognize_path("", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1099 1100 1101
  end

  def test_namespace
1102
    set.draw do
1103

1104 1105
      namespace 'api' do
        match 'inventory' => 'products#inventory'
1106
      end
1107

1108 1109
    end

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

1115
  def test_namespaced_root_map
1116 1117
    set.draw do
      namespace 'api' do
1118
        root :to => 'products#index'
1119 1120 1121
      end
    end

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

1127
  def test_namespace_with_path_prefix
1128
    set.draw do
1129
      scope :module => "api", :path => "prefix" do
1130
        match 'inventory' => 'products#inventory'
1131
      end
1132 1133
    end

J
Joshua Peek 已提交
1134 1135 1136
    params = set.recognize_path("/prefix/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1137
  end
1138

1139
  def test_namespace_with_blank_path_prefix
1140
    set.draw do
1141
      scope :module => "api", :path => "" do
1142
        match 'inventory' => 'products#inventory'
1143 1144 1145
      end
    end

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

1151
  def test_generate_changes_controller_module
1152
    set.draw { match ':controller/:action/:id' }
1153
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
1154 1155 1156

    assert_equal "/foo/bar/baz/7",
        url_for(set, { :controller => "foo/bar", :action => "baz", :id => 7 }, current)
1157 1158 1159
  end

  def test_id_is_sticky_when_it_ought_to_be
1160 1161
    set.draw do
      match ':controller/:id/:action'
1162
    end
1163

1164
    url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" })
1165 1166
    assert_equal "/people/7/destroy", url
  end
1167

1168
  def test_use_static_path_when_possible
1169 1170 1171
    set.draw do
      match 'about' => "welcome#about"
      match ':controller/:action/:id'
1172 1173
    end

1174 1175 1176
    url = url_for(set, { :controller => "welcome", :action => "about" },
      { :controller => "welcome", :action => "get", :id => "7" })

1177 1178
    assert_equal "/about", url
  end
1179

1180
  def test_generate
1181
    set.draw { match ':controller/:action/:id' }
1182

1183
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1184
    assert_equal "/foo/bar/7?x=y",     url_for(set, args)
1185 1186 1187
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1188

1189
  def test_generate_with_path_prefix
1190 1191 1192 1193 1194
    set.draw do
      scope "my" do
        match ':controller(/:action(/:id))'
      end
    end
1195

1196
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1197
    assert_equal "/my/foo/bar/7?x=y", url_for(set, args)
1198 1199
  end

1200
  def test_generate_with_blank_path_prefix
1201 1202 1203 1204 1205
    set.draw do
      scope "" do
        match ':controller(/:action(/:id))'
      end
    end
1206 1207

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

1211
  def test_named_routes_are_never_relative_to_modules
1212
    set.draw do
1213 1214 1215
      match "/connection/manage(/:action)" => 'connection/manage#index'
      match "/connection/connection" => "connection/connection#index"
      match '/connection' => 'connection#index', :as => 'family_connection'
1216
    end
1217

1218
    url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' })
1219 1220
    assert_equal "/connection/connection", url

1221
    url = url_for(set, { :use_route => :family_connection, :controller => "connection" }, { :controller => 'connection/manage' })
1222 1223 1224 1225
    assert_equal "/connection", url
  end

  def test_action_left_off_when_id_is_recalled
1226
    set.draw do
1227
      match ':controller(/:action(/:id))'
1228
    end
1229
    assert_equal '/books', url_for(set,
1230 1231
      {:controller => 'books', :action => 'index'},
      {:controller => 'books', :action => 'show', :id => '10'}
1232 1233
    )
  end
1234

1235
  def test_query_params_will_be_shown_when_recalled
1236 1237
    set.draw do
      match 'show_weblog/:parameter' => 'weblog#show'
1238
      match ':controller(/:action(/:id))'
1239
    end
1240
    assert_equal '/weblog/edit?parameter=1', url_for(set,
1241
      {:action => 'edit', :parameter => 1},
1242
      {:controller => 'weblog', :action => 'show', :parameter => 1}
1243 1244
    )
  end
1245

1246
  def test_format_is_not_inherit
1247
    set.draw do
1248
      match '/posts(.:format)' => 'posts#index'
1249 1250
    end

1251
    assert_equal '/posts', url_for(set,
1252 1253 1254 1255
      {:controller => 'posts'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )

1256
    assert_equal '/posts.xml', url_for(set,
1257 1258 1259 1260 1261
      {:controller => 'posts', :format => 'xml'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )
  end

1262
  def test_expiry_determination_should_consider_values_with_to_param
1263
    set.draw { match 'projects/:project_id/:controller/:action' }
1264 1265 1266
    assert_equal '/projects/1/weblog/show', url_for(set,
      { :action => 'show', :project_id => 1 },
      { :controller => 'weblog', :action => 'show', :project_id => '1' })
1267
  end
1268

1269
  def test_named_route_in_nested_resource
1270 1271
    set.draw do
      resources :projects do
1272 1273 1274
        member do
          match 'milestones' => 'milestones#index', :as => 'milestones'
        end
1275 1276
      end
    end
1277

J
Joshua Peek 已提交
1278 1279 1280
    params = set.recognize_path("/projects/1/milestones", :method => :get)
    assert_equal("milestones", params[:controller])
    assert_equal("index", params[:action])
1281
  end
1282

1283 1284
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
1285 1286
      set.draw do
        namespace :admin do
1287
          root :to => "home#index"
1288 1289 1290
        end
      end
    end
1291
  end
1292

1293 1294
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
1295 1296
      set.draw do
        namespace 'admin' do
1297
          root :to => "home#index"
1298 1299 1300
        end
      end
    end
1301
  end
1302

1303
  def test_route_constraints_with_unsupported_regexp_options_must_error
1304
    assert_raise ArgumentError do
1305 1306
      set.draw do
        match 'page/:name' => 'pages#show',
1307
          :constraints => { :name => /(david|jamis)/m }
1308
      end
1309
    end
1310
  end
1311

1312
  def test_route_constraints_with_supported_options_must_not_error
1313
    assert_nothing_raised do
1314
      set.draw do
1315
        match 'page/:name' => 'pages#show',
1316
          :constraints => { :name => /(david|jamis)/i }
1317 1318
      end
    end
1319
    assert_nothing_raised do
1320 1321
      set.draw do
        match 'page/:name' => 'pages#show',
1322
          :constraints => { :name => / # Desperately overcommented regexp
1323 1324 1325 1326
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
1327
                                      )/x }
1328 1329
      end
    end
1330
  end
1331

1332
  def test_route_requirement_recognize_with_ignore_case
1333 1334 1335
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1336 1337
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1338
    assert_raise ActionController::RoutingError do
1339
      set.recognize_path('/page/davidjamis')
1340
    end
1341 1342
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1343

1344
  def test_route_requirement_generate_with_ignore_case
1345 1346 1347
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1348
    end
1349

1350
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' })
J
Jeremy Kemper 已提交
1351 1352
    assert_equal "/page/david", url
    assert_raise ActionController::RoutingError do
1353
      url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' })
J
Jeremy Kemper 已提交
1354
    end
1355
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
J
Jeremy Kemper 已提交
1356
    assert_equal "/page/JAMIS", url
1357
  end
J
Jeremy Kemper 已提交
1358

1359
  def test_route_requirement_recognize_with_extended_syntax
1360 1361 1362
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => / # Desperately overcommented regexp
1363 1364 1365 1366 1367 1368 1369 1370
                                    ( #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'))
1371
    assert_raise ActionController::RoutingError do
1372 1373
      set.recognize_path('/page/david #The Creator')
    end
1374
    assert_raise ActionController::RoutingError do
1375
      set.recognize_path('/page/David')
1376 1377
    end
  end
1378

1379
  def test_route_requirement_with_xi_modifiers
1380
    set.draw do
1381
      match 'page/:name' => 'pages#show',
1382
        :constraints => {:name => / # Desperately overcommented regexp
1383 1384 1385 1386 1387
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1388
    end
1389

1390 1391
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'},
        set.recognize_path('/page/JAMIS'))
1392

1393 1394
    assert_equal "/page/JAMIS",
        url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
1395
  end
1396 1397

  def test_routes_with_symbols
1398 1399 1400
    set.draw do
      match 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol
      match 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named
1401 1402 1403 1404 1405
    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

1406
  def test_regexp_chunk_should_add_question_mark_for_optionals
1407 1408 1409
    set.draw do
      match '/' => 'foo#index'
      match '/hello' => 'bar#index'
J
Joshua Peek 已提交
1410
    end
1411

1412 1413
    assert_equal '/',      url_for(set, { :controller => 'foo' })
    assert_equal '/hello', url_for(set, { :controller => 'bar' })
1414

J
Joshua Peek 已提交
1415 1416
    assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/'))
    assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello'))
1417 1418 1419
  end

  def test_assign_route_options_with_anchor_chars
1420 1421
    set.draw do
      match '/cars/:action/:person/:car/', :controller => 'cars'
J
Joshua Peek 已提交
1422
    end
1423

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

J
Joshua Peek 已提交
1426
    assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2'))
1427 1428 1429
  end

  def test_segmentation_of_dot_path
1430 1431
    set.draw do
      match '/books/:action.rss', :controller => 'books'
J
Joshua Peek 已提交
1432
    end
1433

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

J
Joshua Peek 已提交
1436
    assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss'))
1437 1438 1439
  end

  def test_segmentation_of_dynamic_dot_path
1440
    set.draw do
1441
      match '/books(/:action(.:format))', :controller => 'books'
J
Joshua Peek 已提交
1442
    end
1443

1444 1445 1446 1447
    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' })
1448

J
Joshua Peek 已提交
1449 1450
    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'))
1451
    assert_equal({:controller => "books", :action => "list"},  set.recognize_path('/books/list'))
J
Joshua Peek 已提交
1452
    assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
1453 1454 1455
  end

  def test_slashes_are_implied
1456 1457
    @set = nil
    set.draw { match("/:controller(/:action(/:id))") }
1458

1459 1460 1461
    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' })
1462

1463 1464
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content'))
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index'))
1465
    assert_equal({:controller => "content", :action => "list"},  set.recognize_path('/content/list'))
1466
    assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1'))
1467 1468 1469
  end

  def test_default_route_recognition
J
Joshua Peek 已提交
1470 1471 1472
    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/')
1473 1474

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

    expected.delete :id
J
Joshua Peek 已提交
1478 1479
    assert_equal expected, default_route_set.recognize_path('/pages/show')
    assert_equal expected, default_route_set.recognize_path('/pages/show/')
1480 1481

    expected[:action] = 'index'
J
Joshua Peek 已提交
1482 1483
    assert_equal expected, default_route_set.recognize_path('/pages/')
    assert_equal expected, default_route_set.recognize_path('/pages')
1484 1485

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
J
Joshua Peek 已提交
1486
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
1487 1488 1489
  end

  def test_default_route_should_omit_default_action
1490
    assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' })
1491 1492 1493
  end

  def test_default_route_should_include_default_action_when_id_present
1494
    assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' })
1495 1496 1497
  end

  def test_default_route_should_work_with_action_but_no_id
1498
    assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' })
1499 1500 1501
  end

  def test_default_route_should_uri_escape_pluses
J
Joshua Peek 已提交
1502 1503
    expected = { :controller => 'pages', :action => 'show', :id => 'hello world' }
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world')
1504
    assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected)
1505 1506

    expected[:id] = 'hello+world'
J
Joshua Peek 已提交
1507 1508
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world')
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld')
1509
    assert_equal '/pages/show/hello+world', url_for(default_route_set, expected)
1510 1511 1512
  end

  def test_build_empty_query_string
1513
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' })
1514 1515 1516
  end

  def test_build_query_string_with_nil_value
1517
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil })
1518 1519 1520
  end

  def test_simple_build_query_string
1521
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' })
1522 1523 1524
  end

  def test_convert_ints_build_query_string
1525
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 })
1526 1527 1528
  end

  def test_escape_spaces_build_query_string
1529
    assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' })
1530 1531 1532
  end

  def test_expand_array_build_query_string
1533
    assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] })
1534 1535 1536
  end

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

1540
  def test_generate_with_default_params
1541
    set.draw do
1542 1543 1544
      match 'dummy/page/:page' => 'dummy#show'
      match 'dummy/dots/page.:page' => 'dummy#dots'
      match 'ibocorp(/:page)' => 'ibocorp#show',
1545 1546
                             :constraints => { :page => /\d+/ },
                             :defaults => { :page => 1 }
1547

1548
      match ':controller/:action/:id'
1549 1550
    end

1551
    assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 })
1552 1553
  end

1554
  def test_generate_with_optional_params_recalls_last_request
1555 1556
    set.draw do
      match "blog/", :controller => "blog", :action => "index"
1557

1558
      match "blog(/:year(/:month(/:day)))",
1559 1560 1561 1562
            :controller => "blog",
            :action => "show_date",
            :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ },
            :day => nil, :month => nil
1563

1564
      match "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/
1565
      match "blog/:controller/:action(/:id)"
1566
      match "*anything", :controller => "blog", :action => "unknown_request"
1567 1568 1569 1570
    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"))
1571 1572
    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"))
1573 1574 1575
    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"))
1576 1577
    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"))
1578 1579 1580

    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)
1581 1582 1583 1584 1585
    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))
1586 1587
  end

J
Joshua Peek 已提交
1588 1589 1590 1591 1592 1593 1594 1595 1596 1597
  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
1598
end
1599

1600
class RackMountIntegrationTests < ActiveSupport::TestCase
1601 1602
  include RoutingTestHelpers

1603 1604
  Model = Struct.new(:to_param)

1605 1606
  Mapping = lambda {
    namespace :admin do
1607
      resources :users, :posts
1608 1609
    end

1610
    namespace 'api' do
1611
      root :to => 'users#index'
1612 1613
    end

1614
    match '/blog(/:year(/:month(/:day)))' => 'posts#show_date',
1615
      :constraints => {
1616 1617 1618 1619 1620 1621
        :year => /(19|20)\d\d/,
        :month => /[01]?\d/,
        :day => /[0-3]?\d/
      },
      :day => nil,
      :month => nil
1622

1623
    match 'archive/:year', :controller => 'archive', :action => 'index',
1624
      :defaults => { :year => nil },
1625 1626
      :constraints => { :year => /\d{4}/ },
      :as => "blog"
1627

1628
    resources :people
1629
    match 'legacy/people' => "people#index", :legacy => "true"
1630

1631
    match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol
1632 1633 1634 1635 1636 1637 1638 1639
    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 => {
1640 1641 1642 1643
                  :postalcode => /# Postcode format
                                  \d{5} #Prefix
                                  (-\d{4})? #Suffix
                                  /x
1644
                  }, :as => "geocode"
1645

1646
    match 'news(.:format)' => "news#index"
1647

Ł
Łukasz Strzałkowski 已提交
1648
    match 'comment/:id(/:action)' => "comments#show"
1649 1650 1651
    match 'ws/:controller(/:action(/:id))', :ws => true
    match 'account(/:action)' => "account#subscription"
    match 'pages/:page_id/:controller(/:action(/:id))'
1652
    match ':controller/ping', :action => 'ping'
1653 1654
    match ':controller(/:action(/:id))(.:format)'
    root :to => "news#index"
1655 1656 1657
  }

  def setup
1658
    @routes = ActionDispatch::Routing::RouteSet.new
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
    @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))

1677 1678
    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))
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
    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'))
1698
    assert_equal({:controller => 'foo', :action => 'id_default', :id => 1 }, @routes.recognize_path('/id_default'))
1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
    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'))

1731
    assert_equal({:controller => 'news', :action => 'index' }, @routes.recognize_path('/', :method => :get))
1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783
    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