routing_test.rb 65.3 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
81
    @rs = ::ActionDispatch::Routing::RouteSet.new
82
  end
J
Joshua Peek 已提交
83

84 85 86 87
  def teardown
    @rs.clear!
  end

88 89 90 91 92 93
  def test_draw_with_block_arity_one_raises
    assert_raise(RuntimeError) do
      @rs.draw { |map| map.match '/:controller(/:action(/:id))' }
    end
  end

94
  def test_default_setup
95
    @rs.draw { match '/:controller(/:action(/:id))' }
96
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
97
    assert_equal({:controller => "content", :action => 'list'},  rs.recognize_path("/content/list"))
98 99 100 101
    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"))

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

104 105
    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' })
106

107 108
    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' })
109 110 111 112
  end

  def test_ignores_leading_slash
    @rs.clear!
113
    @rs.draw { match '/:controller(/:action(/:id))'}
114 115 116 117 118
    test_default_setup
  end

  def test_time_recognition
    # We create many routes to make situation more realistic
119
    @rs = ::ActionDispatch::Routing::RouteSet.new
120
    @rs.draw {
121
      root :to => "search#new", :as => "frontpage"
122 123 124 125 126
      resources :videos do
        resources :comments
        resource  :file,      :controller => 'video_file'
        resource  :share,     :controller => 'video_shares'
        resource  :abuse,     :controller => 'video_abuses'
127
      end
128 129 130
      resources :abuses, :controller => 'video_abuses'
      resources :video_uploads
      resources :video_visits
131

132 133 134
      resources :users do
        resource  :settings
        resources :videos
135
      end
136 137
      resources :channels do
        resources :videos, :controller => 'channel_videos'
138
      end
139 140 141 142 143
      resource  :session
      resource  :lost_password
      match 'search' => 'search#index', :as => 'search'
      resources :pages
      match ':controller/:action/:id'
144 145
    }
  end
146

147
  def test_route_with_colon_first
148 149 150
    rs.draw do
      match '/:controller/:action/:id', :action => 'index', :id => nil
      match ':url', :controller => 'tiny_url', :action => 'translate'
151
    end
152 153 154
  end

  def test_route_with_regexp_for_controller
155
    rs.draw do
156 157
      match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/
      match '/:controller(/:action(/:id))'
158
    end
159

160 161
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
162 163 164 165 166
    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" })
167
  end
168

169
  def test_route_with_regexp_and_captures_for_controller
170
    rs.draw do
171
      match '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/
172 173 174
    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"))
175
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
176 177
  end

178
  def test_route_with_regexp_and_dot
179 180 181 182 183 184
    rs.draw do
      match ':controller/:action/:file',
                :controller => /admin|user/,
                :action => /upload|download/,
                :defaults => {:file => nil},
                :constraints => {:file => %r{[^/]+(\.[^/]+)?}}
185 186 187
    end
    # Without a file extension
    assert_equal '/user/download/file',
188 189 190
      url_for(rs, { :controller => "user", :action => "download", :file => "file" })

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

193 194
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
195 196 197
      url_for(rs, { :controller => "user", :action => "download", :file => "file.jpg" })

    assert_equal({:controller => "user", :action => "download", :file => "file.jpg"},
198 199
      rs.recognize_path("/user/download/file.jpg"))
  end
200

201
  def test_basic_named_route
202
    rs.draw do
203
      root :to => 'content#list', :as => 'home'
204
    end
205
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
206
  end
207

208
  def test_named_route_with_option
209 210
    rs.draw do
      match 'page/:title' => 'content#show_page', :as => 'page'
211
    end
212

213
    assert_equal("http://test.host/page/new%20stuff",
214
        setup_for_named_route.send(:page_url, :title => 'new stuff'))
215
  end
216

217
  def test_named_route_with_default
218 219
    rs.draw do
      match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'
220
    end
221

222 223
    assert_equal("http://test.host/page/AboutRails",
        setup_for_named_route.send(:page_url, :title => "AboutRails"))
224
  end
225

226
  def test_named_route_with_path_prefix
227
    rs.draw do
228 229 230
      scope "my" do
        match 'page' => 'content#show_page', :as => 'page'
      end
231
    end
232

233
    assert_equal("http://test.host/my/page",
234
        setup_for_named_route.send(:page_url))
235
  end
236

237
  def test_named_route_with_blank_path_prefix
238
    rs.draw do
239 240 241
      scope "" do
        match 'page' => 'content#show_page', :as => 'page'
      end
242
    end
243

244
    assert_equal("http://test.host/page",
245
        setup_for_named_route.send(:page_url))
246 247
  end

248
  def test_named_route_with_nested_controller
249
    rs.draw do
250
      match 'admin/user' => 'admin/user#index', :as => "users"
251
    end
252

253
    assert_equal("http://test.host/admin/user",
254
        setup_for_named_route.send(:users_url))
255
  end
256

257
  def test_optimised_named_route_with_host
258
    rs.draw do
259
      match 'page' => 'content#show_page', :as => 'pages', :host => 'foo.com'
260
    end
261 262 263 264 265 266 267 268 269
    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)
270
  end
271

272
  def setup_for_named_route
273
    MockController.build(rs.url_helpers).new
274
  end
275

276
  def test_named_route_without_hash
277 278
    rs.draw do
      match ':controller/:action/:id', :as => 'normal'
279
    end
280
  end
281

282
  def test_named_route_root
283 284
    rs.draw do
      root :to => "hello#index"
285
    end
286 287 288
    routes = setup_for_named_route
    assert_equal("http://test.host/", routes.send(:root_url))
    assert_equal("/", routes.send(:root_path))
289
  end
290

291
  def test_named_route_with_regexps
292 293
    rs.draw do
      match 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',
294
        :year => /\d+/, :month => /\d+/, :day => /\d+/
295
      match ':controller/:action/:id'
296
    end
297 298 299 300 301

    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)
302
  end
303

304
  def test_changing_controller
305
    @rs.draw { match ':controller/:action/:id' }
306

307 308 309
    assert_equal '/admin/stuff/show/10',
        url_for(rs, {:controller => 'stuff', :action => 'show', :id => 10},
                    {:controller => 'admin/user', :action => 'index'})
310
  end
311

312
  def test_paths_escaped
313 314 315
    rs.draw do
      match 'file/*path' => 'content#show_file', :as => 'path'
      match ':controller/:action/:id'
316
    end
317

318 319 320
    # 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"
321
    assert_equal 'hello+world/how+are+you?', results[:path]
322

323 324 325
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
326
    assert_equal 'hello world/how are you?', results[:path]
327
  end
328

329
  def test_paths_slashes_unescaped_with_ordered_parameters
330 331
    rs.draw do
      match '/file/*path' => 'content#index', :as => 'path'
332
    end
333

334
    # No / to %2F in URI, only for query params.
335
    assert_equal("/file/hello/world", setup_for_named_route.send(:path_path, ['hello', 'world']))
336
  end
337

338
  def test_non_controllers_cannot_be_matched
339 340
    rs.draw do
      match ':controller/:action/:id'
341
    end
342
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
343
  end
344

345 346
  def test_should_list_options_diff_when_routing_constraints_dont_match
    rs.draw do
347
      match 'post/:id' => 'post#show', :constraints => { :id => /\d+/ }, :as => 'post'
348
    end
349 350 351
    assert_raise(ActionController::RoutingError) do
      url_for(rs, { :controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post" })
    end
352 353 354
  end

  def test_dynamic_path_allowed
355 356
    rs.draw do
      match '*path' => 'content#show_file'
357
    end
358

359 360
    assert_equal '/pages/boo',
        url_for(rs, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
361
  end
362

363
  def test_dynamic_recall_paths_allowed
364 365
    rs.draw do
      match '*path' => 'content#show_file'
366 367
    end

368 369
    assert_equal '/pages/boo',
        url_for(rs, {}, { :controller => 'content', :action => 'show_file', :path => %w(pages boo) })
370
  end
371

372
  def test_backwards
373
    rs.draw do
374 375
      match 'page/:id(/:action)' => 'pages#show'
      match ':controller(/:action(/:id))'
376 377
    end

378 379 380
    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' })
381 382 383
  end

  def test_route_with_fixnum_default
384
    rs.draw do
385
      match 'page(/:id)' => 'content#show_page', :id => 1
386
      match ':controller/:action/:id'
387 388
    end

389 390 391 392
    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 })
393

394
    assert_equal({:controller => "content", :action => 'show_page', :id => 1 }, rs.recognize_path("/page"))
395 396 397 398 399 400
    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
401 402 403
    rs.draw do
      match 'page/:id' => 'content#show_page', :id => 1
      match ':controller/:action/:id'
404 405
    end

406 407
    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"))
408

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

413 414
    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}"))
415
  end
416

417
  def test_action_expiry
418
    @rs.draw { match ':controller(/:action(/:id))' }
419
    assert_equal '/content', url_for(rs, { :controller => 'content' }, { :controller => 'content', :action => 'show' })
420
  end
421

422
  def test_requirement_should_prevent_optional_id
423 424
    rs.draw do
      match 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'
425 426
    end

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

429
    assert_raise ActionController::RoutingError do
430
      url_for(rs, { :controller => 'post', :action => 'show' })
431
    end
432
  end
433

434
  def test_both_requirement_and_optional
435
    rs.draw do
436
      match('test(/:year)' => 'post#show', :as => 'blog',
437
        :defaults => { :year => nil },
438
        :constraints => { :year => /\d{4}/ }
439
      )
440
      match ':controller/:action/:id'
441
    end
442

443 444
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show' })
    assert_equal '/test', url_for(rs, { :controller => 'post', :action => 'show', :year => nil })
445

446
    assert_equal("http://test.host/test", setup_for_named_route.send(:blog_url))
447
  end
448

449
  def test_set_to_nil_forgets
450
    rs.draw do
451
      match 'pages(/:year(/:month(/:day)))' => 'content#list_pages', :month => nil, :day => nil
452
      match ':controller/:action/:id'
453 454
    end

455
    assert_equal '/pages/2005',
456
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005 })
457
    assert_equal '/pages/2005/6',
458
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6 })
459
    assert_equal '/pages/2005/6/12',
460
      url_for(rs, { :controller => 'content', :action => 'list_pages', :year => 2005, :month => 6, :day => 12 })
461

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

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

468
    assert_equal '/pages/2005',
469
      url_for(rs, { :day => nil, :month => nil }, { :controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12' })
470
  end
471

472
  def test_root_url_generation_with_controller_and_action
473
    rs.draw do
474
      root :to => "content#index"
475 476
    end

477 478
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
479
  end
480

481
  def test_named_root_url_generation_with_controller_and_action
482
    rs.draw do
483
       root :to => "content#index", :as => 'home'
484 485
    end

486 487
    assert_equal '/', url_for(rs, { :controller => 'content', :action => 'index' })
    assert_equal '/', url_for(rs, { :controller => 'content' })
488

489
    assert_equal("http://test.host/", setup_for_named_route.send(:home_url))
490
  end
491

492
  def test_named_route_method
493 494
    rs.draw do
      match 'categories' => 'content#categories', :as => 'categories'
495
      match ':controller(/:action(/:id))'
496 497
    end

498 499
    assert_equal '/categories', url_for(rs, { :controller => 'content', :action => 'categories' })
    assert_equal '/content/hi', url_for(rs, { :controller => 'content', :action => 'hi' })
500 501 502 503 504 505
  end

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

507
  def test_nil_defaults
508 509
    rs.draw do
      match 'journal' => 'content#list_journal',
510
        :date => nil, :user_id => nil
511
      match ':controller/:action/:id'
512
    end
513

514 515 516 517 518 519
    assert_equal '/journal', url_for(rs, {
      :controller => 'content',
      :action => 'list_journal',
      :date => nil,
      :user_id => nil
    })
520
  end
521

522
  def setup_request_method_routes_for(method)
523
    rs.draw do
524 525 526 527
      match '/match' => 'books#get', :via => :get
      match '/match' => 'books#post', :via => :post
      match '/match' => 'books#put', :via => :put
      match '/match' => 'books#delete', :via => :delete
528
    end
529
  end
530

531 532
  %w(GET POST PUT DELETE).each do |request_method|
    define_method("test_request_method_recognized_with_#{request_method}") do
533
      setup_request_method_routes_for(request_method)
J
Joshua Peek 已提交
534 535
      params = rs.recognize_path("/match", :method => request_method)
      assert_equal request_method.downcase, params[:action]
536 537
    end
  end
538

539
  def test_recognize_array_of_methods
540
    rs.draw do
541
      match '/match' => 'books#get_or_post', :via => [:get, :post]
542
      match '/match' => 'books#not_get_or_post'
543 544
    end

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

J
Joshua Peek 已提交
548 549
    params = rs.recognize_path("/match", :method => :put)
    assert_equal 'not_get_or_post', params[:action]
550
  end
551

552
  def test_subpath_recognized
553 554 555 556 557
    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'
558 559
    end

560 561 562
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
563

564 565 566 567 568 569 570 571 572 573 574 575
    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
576

577
  def test_subpath_generated
578 579 580 581
    rs.draw do
      match '/books/:id/edit'    => 'subpath_books#edit'
      match '/items/:id/:action' => 'subpath_books'
      match '/posts/new/:action' => 'subpath_books'
582 583
    end

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

589 590
  def test_failed_constraints_raises_exception_with_violated_constraints
    rs.draw do
591
      match 'foos/:id' => 'foos#show', :as => 'foo_with_requirement', :constraints => { :id => /\d+/ }
592 593
    end

594
    assert_raise(ActionController::RoutingError) do
595
      setup_for_named_route.send(:foo_with_requirement_url, "I am Against the constraints")
596 597
    end
  end
598

599
  def test_routes_changed_correctly_after_clear
600
    rs = ::ActionDispatch::Routing::RouteSet.new
601 602 603 604 605 606
    rs.draw do
      match 'ca' => 'ca#aa'
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
607 608
    end

609
    hash = rs.recognize_path "/cc"
610

611 612
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
613

614 615 616 617 618
    rs.draw do
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
619 620
    end

621
    hash = rs.recognize_path "/cc"
622

623 624 625 626
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
  end
end
627

628
class RouteSetTest < ActiveSupport::TestCase
629 630
  include RoutingTestHelpers

631 632 633
  def set
    @set ||= ROUTING::RouteSet.new
  end
634

635 636 637
  def request
    @request ||= ActionController::TestRequest.new
  end
638

639 640
  def default_route_set
    @default_route_set ||= begin
J
Joshua Peek 已提交
641
      set = ROUTING::RouteSet.new
642
      set.draw do
643
        match '/:controller(/:action(/:id))'
644 645 646 647 648
      end
      set
    end
  end

649
  def test_generate_extras
650
    set.draw { match ':controller/(:action(/:id))' }
651 652
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
653
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
654
  end
655

656
  def test_extra_keys
657
    set.draw { match ':controller/:action/:id' }
658
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
659
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
660
  end
661

662
  def test_generate_extras_not_first
663 664 665
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
666
    end
667 668
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
669
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
670
  end
671

672
  def test_generate_not_first
673 674 675
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
676
    end
677 678
    assert_equal "/foo/bar/15?this=hello",
        url_for(set, { :controller => "foo", :action => "bar", :id => 15, :this => "hello" })
679
  end
680

681
  def test_extra_keys_not_first
682 683 684
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
685
    end
686
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
687
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
688
  end
689

690 691
  def test_draw
    assert_equal 0, set.routes.size
692 693
    set.draw do
      match '/hello/world' => 'a#b'
694
    end
695 696
    assert_equal 1, set.routes.size
  end
697

698 699
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
700 701
    set.draw do
      match '/users/index' => 'users#index'
702
    end
703
    set.recognize_path('/users/index', :method => :get)
704 705 706
    assert_equal 1, set.routes.size
  end

707 708
  def test_named_draw
    assert_equal 0, set.routes.size
709 710
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
711
    end
712 713 714
    assert_equal 1, set.routes.size
    assert_equal set.routes.first, set.named_routes[:hello]
  end
715

716
  def test_earlier_named_routes_take_precedence
717 718 719
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
      match '/hello'       => 'a#b', :as => 'hello'
720
    end
721
    assert_equal set.routes.first, set.named_routes[:hello]
722
  end
723

724
  def setup_named_route_test
725
    set.draw do
726 727 728
      match '/people(/:id)' => 'people#show', :as => 'show'
      match '/people' => 'people#index', :as => 'index'
      match '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi'
729
      match '/admin/users' => 'admin/users#index', :as => "users"
730 731
    end

732
    MockController.build(set.url_helpers).new
733
  end
734

735 736 737 738
  def test_named_route_hash_access_method
    controller = setup_named_route_test

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

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

    assert_equal(
747
      { :controller => 'people', :action => 'show', :id => 5, :use_route => "show", :only_path => true },
748 749
      controller.send(:hash_for_show_path, :id => 5)
    )
750 751
  end

752 753
  def test_named_route_url_method
    controller = setup_named_route_test
754

755 756
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
757

758 759
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
760

761 762
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
763
    assert_equal '/admin/users', url_for(set, controller.send(:hash_for_users_url), { :controller => 'users', :action => 'index' })
764
  end
765

766 767
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
768

769 770
    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')
771

772 773
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
774

775 776
    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')
777

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

781 782
    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')
783

784 785 786
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
787

788 789 790 791
  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
792

793 794 795 796
  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
797

798 799 800 801
  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
802

803 804 805 806 807
  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
808

809 810 811 812 813
  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
814

815 816 817 818 819
  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
820

821 822 823 824 825
  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
826

827
  def test_draw_default_route
828 829
    set.draw do
      match '/:controller/:action/:id'
J
Joshua Peek 已提交
830
    end
831

J
Joshua Peek 已提交
832
    assert_equal 1, set.routes.size
833

834 835
    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 })
836

J
Joshua Peek 已提交
837 838
    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/'))
839
  end
840

841
  def test_route_with_parameter_shell
842 843
    set.draw do
      match 'page/:id' => 'pages#show', :id => /\d+/
844
      match '/:controller(/:action(/:id))'
J
Joshua Peek 已提交
845
    end
846

J
Joshua Peek 已提交
847 848 849
    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'))
850

J
Joshua Peek 已提交
851 852
    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'))
853
  end
854

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

863
  def test_route_constraints_with_anchor_chars_are_invalid
864
    assert_raise ArgumentError do
865 866
      set.draw do
        match 'page/:id' => 'pages#show', :id => /^\d+/
867
      end
868
    end
869
    assert_raise ArgumentError do
870 871
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\A\d+/
872 873
      end
    end
874
    assert_raise ArgumentError do
875 876
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+$/
877 878
      end
    end
879
    assert_raise ArgumentError do
880 881
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\Z/
882 883
      end
    end
884
    assert_raise ArgumentError do
885 886
      set.draw do
        match 'page/:id' => 'pages#show', :id => /\d+\z/
887
      end
888 889
    end
  end
890

891
  def test_route_constraints_with_options_method_condition_is_valid
892
    assert_nothing_raised do
893
      set.draw do
894
        match 'valid/route' => 'pages#show', :via => :options
895 896 897 898
      end
    end
  end

899
  def test_recognize_with_encoded_id_and_regex
900 901
    set.draw do
      match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/
902
    end
903

904 905 906 907
    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

908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
  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])

926
    assert_raise(ActionController::UnknownHttpMethod) {
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
      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

947
  def test_recognize_with_alias_in_conditions
948
    set.draw do
949 950
      match "/people" => 'people#index', :as => 'people', :via => :get
      root :to => "people#index"
951
    end
952

J
Joshua Peek 已提交
953 954 955
    params = set.recognize_path("/people", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
956

J
Joshua Peek 已提交
957 958 959
    params = set.recognize_path("/", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
960
  end
961

962
  def test_typo_recognition
963 964
    set.draw do
      match 'articles/:year/:month/:day/:title' => 'articles#permalink',
965
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
966
    end
967

J
Joshua Peek 已提交
968 969 970 971 972 973
    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])
974
  end
975

976 977
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
978
    set.draw do
979
      match '/profile' => 'profile#index'
980 981
    end

982
    set.recognize_path("/profile") rescue nil
983

984 985 986 987
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
988
    set.draw do
989 990
      get "people/:id" => "people#show", :as => "person"
      put "people/:id" => "people#update"
991
      get "people/:id(.:format)" => "people#show"
992 993
    end

J
Joshua Peek 已提交
994 995 996
    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
997

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

J
Joshua Peek 已提交
1001 1002 1003
    params = set.recognize_path("/people/5.png", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1004
    assert_equal("png", params[:format])
1005 1006 1007
  end

  def test_generate_with_default_action
1008
    set.draw do
1009
      match "/people", :controller => "people", :action => "index"
1010
      match "/people/list", :controller => "people", :action => "list"
1011 1012
    end

1013
    url = url_for(set, { :controller => "people", :action => "list" })
1014 1015
    assert_equal "/people/list", url
  end
1016

1017
  def test_root_map
1018
    set.draw { root :to => 'people#index' }
1019

J
Joshua Peek 已提交
1020 1021 1022
    params = set.recognize_path("", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1023 1024 1025
  end

  def test_namespace
1026
    set.draw do
1027

1028 1029
      namespace 'api' do
        match 'inventory' => 'products#inventory'
1030
      end
1031

1032 1033
    end

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

1039
  def test_namespaced_root_map
1040 1041
    set.draw do
      namespace 'api' do
1042
        root :to => 'products#index'
1043 1044 1045
      end
    end

J
Joshua Peek 已提交
1046 1047 1048
    params = set.recognize_path("/api", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("index", params[:action])
1049
  end
1050

1051
  def test_namespace_with_path_prefix
1052
    set.draw do
1053
      scope :module => "api", :path => "prefix" do
1054
        match 'inventory' => 'products#inventory'
1055
      end
1056 1057
    end

J
Joshua Peek 已提交
1058 1059 1060
    params = set.recognize_path("/prefix/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1061
  end
1062

1063
  def test_namespace_with_blank_path_prefix
1064
    set.draw do
1065
      scope :module => "api", :path => "" do
1066
        match 'inventory' => 'products#inventory'
1067 1068 1069
      end
    end

J
Joshua Peek 已提交
1070 1071 1072
    params = set.recognize_path("/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1073 1074
  end

1075
  def test_generate_changes_controller_module
1076
    set.draw { match ':controller/:action/:id' }
1077
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
1078 1079 1080

    assert_equal "/foo/bar/baz/7",
        url_for(set, { :controller => "foo/bar", :action => "baz", :id => 7 }, current)
1081 1082 1083
  end

  def test_id_is_sticky_when_it_ought_to_be
1084 1085
    set.draw do
      match ':controller/:id/:action'
1086
    end
1087

1088
    url = url_for(set, { :action => "destroy" }, { :controller => "people", :action => "show", :id => "7" })
1089 1090
    assert_equal "/people/7/destroy", url
  end
1091

1092
  def test_use_static_path_when_possible
1093 1094 1095
    set.draw do
      match 'about' => "welcome#about"
      match ':controller/:action/:id'
1096 1097
    end

1098 1099 1100
    url = url_for(set, { :controller => "welcome", :action => "about" },
      { :controller => "welcome", :action => "get", :id => "7" })

1101 1102
    assert_equal "/about", url
  end
1103

1104
  def test_generate
1105
    set.draw { match ':controller/:action/:id' }
1106

1107
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1108
    assert_equal "/foo/bar/7?x=y",     url_for(set, args)
1109 1110 1111
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1112

1113
  def test_generate_with_path_prefix
1114 1115 1116 1117 1118
    set.draw do
      scope "my" do
        match ':controller(/:action(/:id))'
      end
    end
1119

1120
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
1121
    assert_equal "/my/foo/bar/7?x=y", url_for(set, args)
1122 1123
  end

1124
  def test_generate_with_blank_path_prefix
1125 1126 1127 1128 1129
    set.draw do
      scope "" do
        match ':controller(/:action(/:id))'
      end
    end
1130 1131

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

1135
  def test_named_routes_are_never_relative_to_modules
1136
    set.draw do
1137 1138 1139
      match "/connection/manage(/:action)" => 'connection/manage#index'
      match "/connection/connection" => "connection/connection#index"
      match '/connection' => 'connection#index', :as => 'family_connection'
1140
    end
1141

1142
    url = url_for(set, { :controller => "connection" }, { :controller => 'connection/manage' })
1143 1144
    assert_equal "/connection/connection", url

1145
    url = url_for(set, { :use_route => :family_connection, :controller => "connection" }, { :controller => 'connection/manage' })
1146 1147 1148 1149
    assert_equal "/connection", url
  end

  def test_action_left_off_when_id_is_recalled
1150
    set.draw do
1151
      match ':controller(/:action(/:id))'
1152
    end
1153
    assert_equal '/books', url_for(set,
1154 1155
      {:controller => 'books', :action => 'index'},
      {:controller => 'books', :action => 'show', :id => '10'}
1156 1157
    )
  end
1158

1159
  def test_query_params_will_be_shown_when_recalled
1160 1161
    set.draw do
      match 'show_weblog/:parameter' => 'weblog#show'
1162
      match ':controller(/:action(/:id))'
1163
    end
1164
    assert_equal '/weblog/edit?parameter=1', url_for(set,
1165
      {:action => 'edit', :parameter => 1},
1166
      {:controller => 'weblog', :action => 'show', :parameter => 1}
1167 1168
    )
  end
1169

1170
  def test_format_is_not_inherit
1171
    set.draw do
1172
      match '/posts(.:format)' => 'posts#index'
1173 1174
    end

1175
    assert_equal '/posts', url_for(set,
1176 1177 1178 1179
      {:controller => 'posts'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )

1180
    assert_equal '/posts.xml', url_for(set,
1181 1182 1183 1184 1185
      {:controller => 'posts', :format => 'xml'},
      {:controller => 'posts', :action => 'index', :format => 'xml'}
    )
  end

1186
  def test_expiry_determination_should_consider_values_with_to_param
1187
    set.draw { match 'projects/:project_id/:controller/:action' }
1188 1189 1190
    assert_equal '/projects/1/weblog/show', url_for(set,
      { :action => 'show', :project_id => 1 },
      { :controller => 'weblog', :action => 'show', :project_id => '1' })
1191
  end
1192

1193
  def test_named_route_in_nested_resource
1194 1195
    set.draw do
      resources :projects do
1196 1197 1198
        member do
          match 'milestones' => 'milestones#index', :as => 'milestones'
        end
1199 1200
      end
    end
1201

J
Joshua Peek 已提交
1202 1203 1204
    params = set.recognize_path("/projects/1/milestones", :method => :get)
    assert_equal("milestones", params[:controller])
    assert_equal("index", params[:action])
1205
  end
1206

1207 1208
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
1209 1210
      set.draw do
        namespace :admin do
1211
          root :to => "home#index"
1212 1213 1214
        end
      end
    end
1215
  end
1216

1217 1218
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
1219 1220
      set.draw do
        namespace 'admin' do
1221
          root :to => "home#index"
1222 1223 1224
        end
      end
    end
1225
  end
1226

1227
  def test_route_constraints_with_unsupported_regexp_options_must_error
1228
    assert_raise ArgumentError do
1229 1230
      set.draw do
        match 'page/:name' => 'pages#show',
1231
          :constraints => { :name => /(david|jamis)/m }
1232
      end
1233
    end
1234
  end
1235

1236
  def test_route_constraints_with_supported_options_must_not_error
1237
    assert_nothing_raised do
1238
      set.draw do
1239
        match 'page/:name' => 'pages#show',
1240
          :constraints => { :name => /(david|jamis)/i }
1241 1242
      end
    end
1243
    assert_nothing_raised do
1244 1245
      set.draw do
        match 'page/:name' => 'pages#show',
1246
          :constraints => { :name => / # Desperately overcommented regexp
1247 1248 1249 1250
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
1251
                                      )/x }
1252 1253
      end
    end
1254
  end
1255

1256
  def test_route_requirement_recognize_with_ignore_case
1257 1258 1259
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1260 1261
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1262
    assert_raise ActionController::RoutingError do
1263
      set.recognize_path('/page/davidjamis')
1264
    end
1265 1266
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1267

1268
  def test_route_requirement_generate_with_ignore_case
1269 1270 1271
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1272
    end
1273

1274
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'david' })
J
Jeremy Kemper 已提交
1275 1276
    assert_equal "/page/david", url
    assert_raise ActionController::RoutingError do
1277
      url_for(set, { :controller => 'pages', :action => 'show', :name => 'davidjamis' })
J
Jeremy Kemper 已提交
1278
    end
1279
    url = url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
J
Jeremy Kemper 已提交
1280
    assert_equal "/page/JAMIS", url
1281
  end
J
Jeremy Kemper 已提交
1282

1283
  def test_route_requirement_recognize_with_extended_syntax
1284 1285 1286
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => / # Desperately overcommented regexp
1287 1288 1289 1290 1291 1292 1293 1294
                                    ( #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'))
1295
    assert_raise ActionController::RoutingError do
1296 1297
      set.recognize_path('/page/david #The Creator')
    end
1298
    assert_raise ActionController::RoutingError do
1299
      set.recognize_path('/page/David')
1300 1301
    end
  end
1302

1303
  def test_route_requirement_with_xi_modifiers
1304
    set.draw do
1305
      match 'page/:name' => 'pages#show',
1306
        :constraints => {:name => / # Desperately overcommented regexp
1307 1308 1309 1310 1311
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1312
    end
1313

1314 1315
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'},
        set.recognize_path('/page/JAMIS'))
1316

1317 1318
    assert_equal "/page/JAMIS",
        url_for(set, { :controller => 'pages', :action => 'show', :name => 'JAMIS' })
1319
  end
1320 1321

  def test_routes_with_symbols
1322 1323 1324
    set.draw do
      match 'unnamed', :controller => :pages, :action => :show, :name => :as_symbol
      match 'named'  , :controller => :pages, :action => :show, :name => :as_symbol, :as => :named
1325 1326 1327 1328 1329
    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

1330
  def test_regexp_chunk_should_add_question_mark_for_optionals
1331 1332 1333
    set.draw do
      match '/' => 'foo#index'
      match '/hello' => 'bar#index'
J
Joshua Peek 已提交
1334
    end
1335

1336 1337
    assert_equal '/',      url_for(set, { :controller => 'foo' })
    assert_equal '/hello', url_for(set, { :controller => 'bar' })
1338

J
Joshua Peek 已提交
1339 1340
    assert_equal({:controller => "foo", :action => "index"}, set.recognize_path('/'))
    assert_equal({:controller => "bar", :action => "index"}, set.recognize_path('/hello'))
1341 1342 1343
  end

  def test_assign_route_options_with_anchor_chars
1344 1345
    set.draw do
      match '/cars/:action/:person/:car/', :controller => 'cars'
J
Joshua Peek 已提交
1346
    end
1347

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

J
Joshua Peek 已提交
1350
    assert_equal({:controller => "cars", :action => "buy", :person => "1", :car => "2"}, set.recognize_path('/cars/buy/1/2'))
1351 1352 1353
  end

  def test_segmentation_of_dot_path
1354 1355
    set.draw do
      match '/books/:action.rss', :controller => 'books'
J
Joshua Peek 已提交
1356
    end
1357

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

J
Joshua Peek 已提交
1360
    assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list.rss'))
1361 1362 1363
  end

  def test_segmentation_of_dynamic_dot_path
1364
    set.draw do
1365
      match '/books(/:action(.:format))', :controller => 'books'
J
Joshua Peek 已提交
1366
    end
1367

1368 1369 1370 1371
    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' })
1372

J
Joshua Peek 已提交
1373 1374
    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'))
1375
    assert_equal({:controller => "books", :action => "list"},  set.recognize_path('/books/list'))
J
Joshua Peek 已提交
1376
    assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
1377 1378 1379
  end

  def test_slashes_are_implied
1380 1381
    @set = nil
    set.draw { match("/:controller(/:action(/:id))") }
1382

1383 1384 1385
    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' })
1386

1387 1388
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content'))
    assert_equal({:controller => "content", :action => "index"}, set.recognize_path('/content/index'))
1389
    assert_equal({:controller => "content", :action => "list"},  set.recognize_path('/content/list'))
1390
    assert_equal({:controller => "content", :action => "show", :id => "1"}, set.recognize_path('/content/show/1'))
1391 1392 1393
  end

  def test_default_route_recognition
J
Joshua Peek 已提交
1394 1395 1396
    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/')
1397 1398

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

    expected.delete :id
J
Joshua Peek 已提交
1402 1403
    assert_equal expected, default_route_set.recognize_path('/pages/show')
    assert_equal expected, default_route_set.recognize_path('/pages/show/')
1404 1405

    expected[:action] = 'index'
J
Joshua Peek 已提交
1406 1407
    assert_equal expected, default_route_set.recognize_path('/pages/')
    assert_equal expected, default_route_set.recognize_path('/pages')
1408 1409

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
J
Joshua Peek 已提交
1410
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
1411 1412 1413
  end

  def test_default_route_should_omit_default_action
1414
    assert_equal '/accounts', url_for(default_route_set, { :controller => 'accounts', :action => 'index' })
1415 1416 1417
  end

  def test_default_route_should_include_default_action_when_id_present
1418
    assert_equal '/accounts/index/20', url_for(default_route_set, { :controller => 'accounts', :action => 'index', :id => '20' })
1419 1420 1421
  end

  def test_default_route_should_work_with_action_but_no_id
1422
    assert_equal '/accounts/list_all', url_for(default_route_set, { :controller => 'accounts', :action => 'list_all' })
1423 1424 1425
  end

  def test_default_route_should_uri_escape_pluses
J
Joshua Peek 已提交
1426 1427
    expected = { :controller => 'pages', :action => 'show', :id => 'hello world' }
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world')
1428
    assert_equal '/pages/show/hello%20world', url_for(default_route_set, expected)
1429 1430

    expected[:id] = 'hello+world'
J
Joshua Peek 已提交
1431 1432
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world')
    assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld')
1433
    assert_equal '/pages/show/hello+world', url_for(default_route_set, expected)
1434 1435 1436
  end

  def test_build_empty_query_string
1437
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo' })
1438 1439 1440
  end

  def test_build_query_string_with_nil_value
1441
    assert_uri_equal '/foo', url_for(default_route_set, { :controller => 'foo', :x => nil })
1442 1443 1444
  end

  def test_simple_build_query_string
1445
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => '1', :y => '2' })
1446 1447 1448
  end

  def test_convert_ints_build_query_string
1449
    assert_uri_equal '/foo?x=1&y=2', url_for(default_route_set, { :controller => 'foo', :x => 1, :y => 2 })
1450 1451 1452
  end

  def test_escape_spaces_build_query_string
1453
    assert_uri_equal '/foo?x=hello+world&y=goodbye+world', url_for(default_route_set, { :controller => 'foo', :x => 'hello world', :y => 'goodbye world' })
1454 1455 1456
  end

  def test_expand_array_build_query_string
1457
    assert_uri_equal '/foo?x%5B%5D=1&x%5B%5D=2', url_for(default_route_set, { :controller => 'foo', :x => [1, 2] })
1458 1459 1460
  end

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

1464
  def test_generate_with_default_params
1465
    set.draw do
1466 1467 1468
      match 'dummy/page/:page' => 'dummy#show'
      match 'dummy/dots/page.:page' => 'dummy#dots'
      match 'ibocorp(/:page)' => 'ibocorp#show',
1469 1470
                             :constraints => { :page => /\d+/ },
                             :defaults => { :page => 1 }
1471

1472
      match ':controller/:action/:id'
1473 1474
    end

1475
    assert_equal '/ibocorp', url_for(set, { :controller => 'ibocorp', :action => "show", :page => 1 })
1476 1477
  end

1478
  def test_generate_with_optional_params_recalls_last_request
1479 1480
    set.draw do
      match "blog/", :controller => "blog", :action => "index"
1481

1482
      match "blog(/:year(/:month(/:day)))",
1483 1484 1485 1486
            :controller => "blog",
            :action => "show_date",
            :constraints => { :year => /(19|20)\d\d/, :month => /[01]?\d/, :day => /[0-3]?\d/ },
            :day => nil, :month => nil
1487

1488
      match "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/
1489
      match "blog/:controller/:action(/:id)"
1490
      match "*anything", :controller => "blog", :action => "unknown_request"
1491 1492 1493 1494
    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"))
1495 1496
    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"))
1497 1498 1499
    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"))
1500 1501
    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"))
1502 1503 1504

    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)
1505 1506 1507 1508 1509
    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))
1510 1511
  end

J
Joshua Peek 已提交
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521
  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
1522
end
1523

1524
class RackMountIntegrationTests < ActiveSupport::TestCase
1525 1526
  include RoutingTestHelpers

1527 1528
  Model = Struct.new(:to_param)

1529 1530
  Mapping = lambda {
    namespace :admin do
1531
      resources :users, :posts
1532 1533
    end

1534
    namespace 'api' do
1535
      root :to => 'users#index'
1536 1537
    end

1538
    match '/blog(/:year(/:month(/:day)))' => 'posts#show_date',
1539
      :constraints => {
1540 1541 1542 1543 1544 1545
        :year => /(19|20)\d\d/,
        :month => /[01]?\d/,
        :day => /[0-3]?\d/
      },
      :day => nil,
      :month => nil
1546

1547
    match 'archive/:year', :controller => 'archive', :action => 'index',
1548
      :defaults => { :year => nil },
1549 1550
      :constraints => { :year => /\d{4}/ },
      :as => "blog"
1551

1552
    resources :people
1553
    match 'legacy/people' => "people#index", :legacy => "true"
1554

1555
    match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol
1556 1557 1558 1559 1560 1561 1562 1563
    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 => {
1564 1565 1566 1567
                  :postalcode => /# Postcode format
                                  \d{5} #Prefix
                                  (-\d{4})? #Suffix
                                  /x
1568
                  }, :as => "geocode"
1569

1570
    match 'news(.:format)' => "news#index"
1571

Ł
Łukasz Strzałkowski 已提交
1572
    match 'comment/:id(/:action)' => "comments#show"
1573 1574 1575
    match 'ws/:controller(/:action(/:id))', :ws => true
    match 'account(/:action)' => "account#subscription"
    match 'pages/:page_id/:controller(/:action(/:id))'
1576
    match ':controller/ping', :action => 'ping'
1577 1578
    match ':controller(/:action(/:id))(.:format)'
    root :to => "news#index"
1579 1580 1581
  }

  def setup
1582
    @routes = ActionDispatch::Routing::RouteSet.new
1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600
    @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))

1601 1602
    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))
1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621
    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'))
1622
    assert_equal({:controller => 'foo', :action => 'id_default', :id => 1 }, @routes.recognize_path('/id_default'))
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
    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'))

1655
    assert_equal({:controller => 'news', :action => 'index' }, @routes.recognize_path('/', :method => :get))
1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
    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