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

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

13
ROUTING = ActionController::Routing
14

15
# See RFC 3986, section 3.3 for allowed path characters.
16 17 18
class UriReservedCharactersRoutingTest < Test::Unit::TestCase
  def setup
    @set = ActionController::Routing::RouteSet.new
19 20
    @set.draw do
      match ':controller/:action/:variable/*additional'
21
    end
22

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

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

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

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

  def test_route_generation_allows_passing_non_string_values_to_generated_helper
48
    assert_equal "/content/action/variable/1/2", @set.generate(:controller => "content",
49 50 51 52
                                                                  :action => "action",
                                                                  :variable => "variable",
                                                                  :additional => [1, 2])
  end
53 54
end

55
class MockController
56 57 58 59 60
  def self.build(helpers)
    Class.new do
      def url_for(options)
        options[:protocol] ||= "http"
        options[:host] ||= "test.host"
61

62 63 64 65 66
        super(options)
      end

      include helpers
    end
67
  end
68
end
69

70 71
class LegacyRouteSetTests < Test::Unit::TestCase
  attr_reader :rs
72

73 74 75
  def setup
    @rs = ::ActionController::Routing::RouteSet.new
  end
J
Joshua Peek 已提交
76

77 78 79 80 81
  def teardown
    @rs.clear!
  end

  def test_default_setup
82
    @rs.draw { match '/:controller(/:action(/:id))' }
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
    assert_equal({:controller => "content", :action => 'index'}, rs.recognize_path("/content"))
    assert_equal({:controller => "content", :action => 'list'}, rs.recognize_path("/content/list"))
    assert_equal({:controller => "content", :action => 'show', :id => '10'}, rs.recognize_path("/content/show/10"))

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

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

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

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

  def test_ignores_leading_slash
    @rs.clear!
100
    @rs.draw { match '/:controller(/:action(/:id))'}
101 102 103 104 105 106
    test_default_setup
  end

  def test_time_recognition
    # We create many routes to make situation more realistic
    @rs = ::ActionController::Routing::RouteSet.new
107 108 109 110 111 112 113
    @rs.draw {
      match '' => "search#new", :as => "frontpage"
      resources :videos do
        resources :comments
        resource  :file,      :controller => 'video_file'
        resource  :share,     :controller => 'video_shares'
        resource  :abuse,     :controller => 'video_abuses'
114
      end
115 116 117
      resources :abuses, :controller => 'video_abuses'
      resources :video_uploads
      resources :video_visits
118

119 120 121
      resources :users do
        resource  :settings
        resources :videos
122
      end
123 124
      resources :channels do
        resources :videos, :controller => 'channel_videos'
125
      end
126 127 128 129 130
      resource  :session
      resource  :lost_password
      match 'search' => 'search#index', :as => 'search'
      resources :pages
      match ':controller/:action/:id'
131 132
    }
  end
133

134
  def test_route_with_colon_first
135 136 137
    rs.draw do
      match '/:controller/:action/:id', :action => 'index', :id => nil
      match ':url', :controller => 'tiny_url', :action => 'translate'
138
    end
139 140 141
  end

  def test_route_with_regexp_for_controller
142
    rs.draw do
143 144
      match ':controller/:admintoken(/:action(/:id))', :controller => /admin\/.+/
      match '/:controller(/:action(/:id))'
145
    end
146 147 148 149 150 151
    assert_equal({:controller => "admin/user", :admintoken => "foo", :action => "index"},
        rs.recognize_path("/admin/user/foo"))
    assert_equal({:controller => "content", :action => "foo"}, rs.recognize_path("/content/foo"))
    assert_equal '/admin/user/foo', rs.generate(:controller => "admin/user", :admintoken => "foo", :action => "index")
    assert_equal '/content/foo', rs.generate(:controller => "content", :action => "foo")
  end
152

153
  def test_route_with_regexp_and_captures_for_controller
154
    rs.draw do
155
      match '/:controller(/:action(/:id))', :controller => /admin\/(accounts|users)/
156 157 158
    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"))
159
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/admin/products") }
160 161
  end

162
  def test_route_with_regexp_and_dot
163 164 165 166 167 168
    rs.draw do
      match ':controller/:action/:file',
                :controller => /admin|user/,
                :action => /upload|download/,
                :defaults => {:file => nil},
                :constraints => {:file => %r{[^/]+(\.[^/]+)?}}
169 170 171 172 173 174 175
    end
    # Without a file extension
    assert_equal '/user/download/file',
      rs.generate(:controller => "user", :action => "download", :file => "file")
    assert_equal(
      {:controller => "user", :action => "download", :file => "file"},
      rs.recognize_path("/user/download/file"))
176

177 178 179 180 181 182 183 184
    # Now, let's try a file with an extension, really a dot (.)
    assert_equal '/user/download/file.jpg',
      rs.generate(
        :controller => "user", :action => "download", :file => "file.jpg")
    assert_equal(
      {:controller => "user", :action => "download", :file => "file.jpg"},
      rs.recognize_path("/user/download/file.jpg"))
  end
185

186
  def test_basic_named_route
187 188
    rs.draw do
      match '' => 'content#list', :as => 'home'
189
    end
190 191 192 193
    x = setup_for_named_route
    assert_equal("http://test.host/",
                 x.send(:home_url))
  end
194

195
  def test_named_route_with_option
196 197
    rs.draw do
      match 'page/:title' => 'content#show_page', :as => 'page'
198
    end
199 200 201 202
    x = setup_for_named_route
    assert_equal("http://test.host/page/new%20stuff",
                 x.send(:page_url, :title => 'new stuff'))
  end
203

204
  def test_named_route_with_default
205 206
    rs.draw do
      match 'page/:title' => 'content#show_page', :title => 'AboutPage', :as => 'page'
207
    end
208 209 210
    x = setup_for_named_route
    assert_equal("http://test.host/page/AboutRails",
                 x.send(:page_url, :title => "AboutRails"))
211

212
  end
213

214
  def test_named_route_with_path_prefix
215
    rs.draw do
216 217 218
      scope "my" do
        match 'page' => 'content#show_page', :as => 'page'
      end
219
    end
220 221 222 223
    x = setup_for_named_route
    assert_equal("http://test.host/my/page",
                 x.send(:page_url))
  end
224

225
  def test_named_route_with_blank_path_prefix
226
    rs.draw do
227 228 229
      scope "" do
        match 'page' => 'content#show_page', :as => 'page'
      end
230
    end
231 232 233 234 235
    x = setup_for_named_route
    assert_equal("http://test.host/page",
                 x.send(:page_url))
  end

236
  def test_named_route_with_nested_controller
237 238
    rs.draw do
      match 'admin/user' => 'admin/user#index'
239
    end
240 241 242 243
    x = setup_for_named_route
    assert_equal("http://test.host/admin/user",
                 x.send(:users_url))
  end
244

245
  def test_optimised_named_route_with_host
246 247
    rs.draw do
      match 'page' => 'content#show_page', :as => 'page', :host => 'foo.com'
248
    end
249 250 251 252
    x = setup_for_named_route
    x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
    x.send(:pages_url)
  end
253

254
  def setup_for_named_route
255
    MockController.build(rs.url_helpers).new
256
  end
257

258
  def test_named_route_without_hash
259 260
    rs.draw do
      match ':controller/:action/:id', :as => 'normal'
261
    end
262
  end
263

264
  def test_named_route_root
265 266
    rs.draw do
      root :to => "hello#index"
267
    end
268 269 270 271
    x = setup_for_named_route
    assert_equal("http://test.host/", x.send(:root_url))
    assert_equal("/", x.send(:root_path))
  end
272

273
  def test_named_route_with_regexps
274 275
    rs.draw do
      match 'page/:year/:month/:day/:title' => 'page#show', :as => 'article',
276
        :year => /\d+/, :month => /\d+/, :day => /\d+/
277
      match ':controller/:action/:id'
278
    end
279 280 281 282 283 284 285 286 287 288
    x = setup_for_named_route
    # assert_equal(
    #   {:controller => 'page', :action => 'show', :title => 'hi', :use_route => :article, :only_path => false},
    #   x.send(:article_url, :title => 'hi')
    # )
    assert_equal(
      "http://test.host/page/2005/6/10/hi",
      x.send(:article_url, :title => 'hi', :day => 10, :year => 2005, :month => 6)
    )
  end
289

290
  def test_changing_controller
291
    @rs.draw { match ':controller/:action/:id' }
292

293 294 295 296 297
    assert_equal '/admin/stuff/show/10', rs.generate(
      {:controller => 'stuff', :action => 'show', :id => 10},
      {:controller => 'admin/user', :action => 'index'}
    )
  end
298

299
  def test_paths_escaped
300 301 302
    rs.draw do
      match 'file/*path' => 'content#show_file', :as => 'path'
      match ':controller/:action/:id'
303
    end
304

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

310 311 312 313 314
    # Use %20 for space instead.
    results = rs.recognize_path "/file/hello%20world/how%20are%20you%3F"
    assert results, "Recognition should have succeeded"
    assert_equal ['hello world', 'how are you?'], results[:path]
  end
315

316
  def test_paths_slashes_unescaped_with_ordered_parameters
317 318
    rs.draw do
      match '/file/*path' => 'content#index', :as => 'path'
319
    end
320

321 322
    # No / to %2F in URI, only for query params.
    x = setup_for_named_route
323
    assert_equal("/file/hello/world", x.send(:path_path, ['hello', 'world']))
324
  end
325

326
  def test_non_controllers_cannot_be_matched
327 328
    rs.draw do
      match ':controller/:action/:id'
329
    end
330
    assert_raise(ActionController::RoutingError) { rs.recognize_path("/not_a/show/10") }
331
  end
332

333
  def test_paths_do_not_accept_defaults
334
    assert_raise(ActionController::RoutingError) do
335 336 337
      rs.draw do
        match 'file/*path' => 'content#show_file', :path => %w(fake default), :as => 'path'
        match ':controller/:action/:id'
338 339 340
      end
    end

341 342 343
    rs.draw do
      match 'file/*path', :to => 'content#show_file', :path => [], :as => 'path'
      match ':controller/:action/:id'
344
    end
345
  end
346

347 348 349
  def test_should_list_options_diff_when_routing_constraints_dont_match
    rs.draw do
      math 'post/:id' => 'post#show', :constraints => {:id => /\d+/}, :as => 'post'
350
    end
351
    assert_raise(ActionController::RoutingError) { rs.generate(:controller => 'post', :action => 'show', :bad_param => "foo", :use_route => "post") }
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', rs.generate(:controller => 'content', :action => 'show_file', :path => %w(pages boo))
  end
361

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

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

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

376 377 378 379 380 381
    assert_equal '/page/20', rs.generate({:id => 20}, {:controller => 'pages', :action => 'show'})
    assert_equal '/page/20', rs.generate(:controller => 'pages', :id => 20, :action => 'show')
    assert_equal '/pages/boo', rs.generate(:controller => 'pages', :action => 'boo')
  end

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

387 388 389 390
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page')
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => 1)
    assert_equal '/page', rs.generate(:controller => 'content', :action => 'show_page', :id => '1')
    assert_equal '/page/10', rs.generate(:controller => 'content', :action => 'show_page', :id => 10)
391

392 393 394 395 396 397 398
    assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page"))
    assert_equal({:controller => "content", :action => 'show_page', :id => '1'}, rs.recognize_path("/page/1"))
    assert_equal({:controller => "content", :action => 'show_page', :id => '10'}, rs.recognize_path("/page/10"))
  end

  # For newer revision
  def test_route_with_text_default
399 400 401
    rs.draw do
      match 'page/:id' => 'content#show_page', :id => 1
      match ':controller/:action/:id'
402 403
    end

404 405
    assert_equal '/page/foo', rs.generate(:controller => 'content', :action => 'show_page', :id => 'foo')
    assert_equal({:controller => "content", :action => 'show_page', :id => 'foo'}, rs.recognize_path("/page/foo"))
406

407
    token = "\321\202\320\265\320\272\321\201\321\202" # 'text' in russian
408
    token.force_encoding(Encoding::BINARY) if token.respond_to?(:force_encoding)
409
    escaped_token = CGI::escape(token)
410

411 412 413
    assert_equal '/page/' + escaped_token, rs.generate(:controller => 'content', :action => 'show_page', :id => token)
    assert_equal({:controller => "content", :action => 'show_page', :id => token}, rs.recognize_path("/page/#{escaped_token}"))
  end
414

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

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

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

427
    assert_raise ActionController::RoutingError do
428
      rs.generate(:controller => 'post', :action => 'show')
429
    end
430
  end
431

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

441 442 443 444 445 446 447
    assert_equal '/test', rs.generate(:controller => 'post', :action => 'show')
    assert_equal '/test', rs.generate(:controller => 'post', :action => 'show', :year => nil)

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

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

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

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

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

468 469 470
    assert_equal '/pages/2005',
      rs.generate({:day => nil, :month => nil}, {:controller => 'content', :action => 'list_pages', :year => '2005', :month => '6', :day => '12'})
  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 479
    assert_equal '/', rs.generate(:controller => 'content', :action => 'index')
    assert_equal '/', rs.generate(:controller => 'content')
  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 '/', rs.generate(:controller => 'content', :action => 'index')
    assert_equal '/', rs.generate(:controller => 'content')
488

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

494 495
  def test_url_generated_when_forgetting_action
    [{:controller => 'content', :action => 'index'}, {:controller => 'content'}].each do |hash|
496 497 498
      rs.draw do
        match '', hash.merge(:as => 'home')
        match ':controller/:action/:id'
499
      end
500 501 502 503 504
      assert_equal '/', rs.generate({:action => nil}, {:controller => 'content', :action => 'hello'})
      assert_equal '/', rs.generate({:controller => 'content'})
      assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
    end
  end
505

506
  def test_named_route_method
507 508 509
    rs.draw do
      match 'categories' => 'content#categories', :as => 'categories'
      match ':controller/:action/:id'
510 511
    end

512 513 514 515 516 517 518 519
    assert_equal '/categories', rs.generate(:controller => 'content', :action => 'categories')
    assert_equal '/content/hi', rs.generate({:controller => 'content', :action => 'hi'})
  end

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

521
  def test_nil_defaults
522 523
    rs.draw do
      match 'journal' => 'content#list_journal',
524
        :date => nil, :user_id => nil
525
      match ':controller/:action/:id'
526
    end
527

528 529
    assert_equal '/journal', rs.generate(:controller => 'content', :action => 'list_journal', :date => nil, :user_id => nil)
  end
530

531
  def setup_request_method_routes_for(method)
532 533 534 535 536
    rs.draw do
      match '/match' => 'books#get', :conditions => { :method => :get }
      match '/match' => 'books#post', :conditions => { :method => :post }
      match '/match' => 'books#put', :conditions => { :method => :put }
      match '/match' => 'books#delete', :conditions => { :method => :delete }
537
    end
538
  end
539

540 541
  %w(GET POST PUT DELETE).each do |request_method|
    define_method("test_request_method_recognized_with_#{request_method}") do
542
      setup_request_method_routes_for(request_method)
J
Joshua Peek 已提交
543 544
      params = rs.recognize_path("/match", :method => request_method)
      assert_equal request_method.downcase, params[:action]
545 546
    end
  end
547

548
  def test_recognize_array_of_methods
549 550 551
    rs.draw do
      match '/match' => 'books#get_or_post', :conditions => { :method => [:get, :post] }
      match '/match' => 'books#not_get_or_post'
552 553
    end

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

J
Joshua Peek 已提交
557 558
    params = rs.recognize_path("/match", :method => :put)
    assert_equal 'not_get_or_post', params[:action]
559
  end
560

561
  def test_subpath_recognized
562 563 564 565 566
    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'
567 568
    end

569 570 571
    hash = rs.recognize_path "/books/17/edit"
    assert_not_nil hash
    assert_equal %w(subpath_books 17 edit), [hash[:controller], hash[:id], hash[:action]]
572

573 574 575 576 577 578 579 580 581 582 583 584
    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
585

586
  def test_subpath_generated
587 588 589 590
    rs.draw do
      match '/books/:id/edit'    => 'subpath_books#edit'
      match '/items/:id/:action' => 'subpath_books'
      match '/posts/new/:action' => 'subpath_books'
591 592
    end

593 594 595 596
    assert_equal "/books/7/edit", rs.generate(:controller => "subpath_books", :id => 7, :action => "edit")
    assert_equal "/items/15/complete", rs.generate(:controller => "subpath_books", :id => 15, :action => "complete")
    assert_equal "/posts/new/preview", rs.generate(:controller => "subpath_books", :action => "preview")
  end
597

598 599 600
  def test_failed_constraints_raises_exception_with_violated_constraints
    rs.draw do
      match 'foos/:id' => 'foos', :as => 'foo_with_requirement', :constraints=>{:id=>/\d+/}
601 602
    end

603
    x = setup_for_named_route
604
    assert_raise(ActionController::RoutingError) do
605
      x.send(:foo_with_requirement_url, "I am Against the constraints")
606 607
    end
  end
608

609 610
  def test_routes_changed_correctly_after_clear
    rs = ::ActionController::Routing::RouteSet.new
611 612 613 614 615 616
    rs.draw do
      match 'ca' => 'ca#aa'
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
617 618
    end

619
    hash = rs.recognize_path "/cc"
620

621 622
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
623

624 625 626 627 628
    rs.draw do
      match 'cb' => 'cb#ab'
      match 'cc' => 'cc#ac'
      match ':controller/:action/:id'
      match ':controller/:action/:id.:format'
629 630
    end

631
    hash = rs.recognize_path "/cc"
632

633 634
    assert_not_nil hash
    assert_equal %w(cc ac), [hash[:controller], hash[:action]]
635

636 637
  end
end
638

639
class RouteSetTest < ActiveSupport::TestCase
640 641 642
  def set
    @set ||= ROUTING::RouteSet.new
  end
643

644 645 646
  def request
    @request ||= ActionController::TestRequest.new
  end
647

648 649
  def default_route_set
    @default_route_set ||= begin
J
Joshua Peek 已提交
650
      set = ROUTING::RouteSet.new
651
      set.draw do
652
        match '/:controller(/:action(/:id))'
653 654 655 656 657
      end
      set
    end
  end

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

665
  def test_extra_keys
666
    set.draw { match ':controller/:action/:id' }
667
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
668
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
669
  end
670

671
  def test_generate_extras_not_first
672 673 674
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
675
    end
676 677
    path, extras = set.generate_extras(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
    assert_equal "/foo/bar/15", path
678
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
679
  end
680

681
  def test_generate_not_first
682 683 684
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
685
    end
686 687
    assert_equal "/foo/bar/15?this=hello", set.generate(:controller => "foo", :action => "bar", :id => 15, :this => "hello")
  end
688

689
  def test_extra_keys_not_first
690 691 692
    set.draw do
      match ':controller/:action/:id.:format'
      match ':controller/:action/:id'
693
    end
694
    extras = set.extra_keys(:controller => "foo", :action => "bar", :id => 15, :this => "hello", :that => "world")
695
    assert_equal %w(that this), extras.map { |e| e.to_s }.sort
696
  end
697

698 699
  def test_draw
    assert_equal 0, set.routes.size
700 701
    set.draw do
      match '/hello/world' => 'a#b'
702
    end
703 704
    assert_equal 1, set.routes.size
  end
705

706 707
  def test_draw_symbol_controller_name
    assert_equal 0, set.routes.size
708 709
    set.draw do
      match '/users/index' => 'users#index'
710
    end
J
Joshua Peek 已提交
711
    params = set.recognize_path('/users/index', :method => :get)
712 713 714
    assert_equal 1, set.routes.size
  end

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

724
  def test_later_named_routes_take_precedence
725 726 727
    set.draw do
      match '/hello/world' => 'a#b', :as => 'hello'
      match '/hello'       => 'a#b', :as => 'hello'
728
    end
729 730
    assert_equal set.routes.last, set.named_routes[:hello]
  end
731

732
  def setup_named_route_test
733
    set.draw do
734 735 736 737
      match '/people(/:id)' => 'people#show', :as => 'show'
      match '/people' => 'people#index', :as => 'index'
      match '/people/go/:foo/:bar/joe(/:id)' => 'people#multi', :as => 'multi'
      match '/admin/users' => 'admin/users#index', :as => 'index'
738 739
    end

740
    MockController.build(set.url_helpers).new
741
  end
742

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
  def test_named_route_hash_access_method
    controller = setup_named_route_test

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

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

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

760 761
  def test_named_route_url_method
    controller = setup_named_route_test
762

763 764
    assert_equal "http://test.host/people/5", controller.send(:show_url, :id => 5)
    assert_equal "/people/5", controller.send(:show_path, :id => 5)
765

766 767
    assert_equal "http://test.host/people", controller.send(:index_url)
    assert_equal "/people", controller.send(:index_path)
768

769 770 771 772
    assert_equal "http://test.host/admin/users", controller.send(:users_url)
    assert_equal '/admin/users', controller.send(:users_path)
    assert_equal '/admin/users', set.generate(controller.send(:hash_for_users_url), {:controller => 'users', :action => 'index'})
  end
773

774 775
  def test_named_route_url_method_with_anchor
    controller = setup_named_route_test
776

777 778
    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')
779

780 781
    assert_equal "http://test.host/people#location", controller.send(:index_url, :anchor => 'location')
    assert_equal "/people#location", controller.send(:index_path, :anchor => 'location')
782

783 784
    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')
785

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

789 790
    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')
791

792 793 794
    assert_equal "http://test.host/people?baz=bar#location",
      controller.send(:index_url, :baz => "bar", :anchor => 'location')
  end
795

796 797 798 799
  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
800

801 802 803 804
  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
805

806 807 808 809
  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
810

811 812 813 814 815
  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
816

817 818 819 820 821
  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
822

823 824 825 826 827
  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
828

829 830 831 832 833
  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
834

835
  def test_draw_default_route
836 837
    set.draw do
      match '/:controller/:action/:id'
J
Joshua Peek 已提交
838
    end
839

J
Joshua Peek 已提交
840
    assert_equal 1, set.routes.size
841

J
Joshua Peek 已提交
842 843
    assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
    assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
844

J
Joshua Peek 已提交
845 846
    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/'))
847
  end
848

849
  def test_route_with_parameter_shell
850 851
    set.draw do
      match 'page/:id' => 'pages#show', :id => /\d+/
852
      match '/:controller(/:action(/:id))'
J
Joshua Peek 已提交
853
    end
854

J
Joshua Peek 已提交
855 856 857
    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'))
858

J
Joshua Peek 已提交
859 860
    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'))
861
  end
862

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_invalid_http_method_is_invalid
892
    assert_raise ArgumentError do
893 894
      set.draw do
        match 'valid/route' => 'pages#show', :conditions => {:method => :invalid}
895 896
      end
    end
897
  end
898

899
  def test_route_constraints_with_options_method_condition_is_valid
900
    assert_nothing_raised do
901 902
      set.draw do
        match 'valid/route' => 'pages#show', :conditions => {:method => :options}
903 904 905 906
      end
    end
  end

907
  def test_route_constraints_with_head_method_condition_is_invalid
908
    assert_raise ArgumentError do
909 910
      set.draw do
        match 'valid/route' => 'pages#show', :conditions => {:method => :head}
911
      end
912 913
    end
  end
914

915
  def test_recognize_with_encoded_id_and_regex
916 917
    set.draw do
      match 'page/:id' => 'pages#show', :id => /[a-zA-Z0-9\+]+/
918
    end
919

920 921 922 923
    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

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
  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])

    assert_raise(ActionController::RoutingError) {
      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

963
  def test_recognize_with_alias_in_conditions
964 965
    set.draw do
      match "/people" => 'people#index', :as => 'people',
966
        :conditions => { :method => :get }
967
      root   :people
968
    end
969

J
Joshua Peek 已提交
970 971 972
    params = set.recognize_path("/people", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
973

J
Joshua Peek 已提交
974 975 976
    params = set.recognize_path("/", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
977
  end
978

979
  def test_typo_recognition
980 981
    set.draw do
      match 'articles/:year/:month/:day/:title' => 'articles#permalink',
982
             :year => /\d{4}/, :day => /\d{1,2}/, :month => /\d{1,2}/
983
    end
984

J
Joshua Peek 已提交
985 986 987 988 989 990
    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])
991
  end
992

993 994
  def test_routing_traversal_does_not_load_extra_classes
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
995
    set.draw do
996
      match '/profile' => 'profile#index'
997 998
    end

J
Joshua Peek 已提交
999
    params = set.recognize_path("/profile") rescue nil
1000

1001 1002 1003 1004
    assert !Object.const_defined?("Profiler__"), "Profiler should not be loaded"
  end

  def test_recognize_with_conditions_and_format
1005
    set.draw do
1006 1007 1008 1009
      map.with_options(:controller => "people") do |people|
        people.person  "/people/:id", :action => "show",    :conditions => { :method => :get }
        people.connect "/people/:id", :action => "update",  :conditions => { :method => :put }
        people.connect "/people/:id.:_format", :action => "show", :conditions => { :method => :get }
1010
      end
1011 1012
    end

J
Joshua Peek 已提交
1013 1014 1015
    params = set.recognize_path("/people/5", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
1016

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

J
Joshua Peek 已提交
1020 1021 1022 1023
    params = set.recognize_path("/people/5.png", :method => :get)
    assert_equal("show", params[:action])
    assert_equal("5", params[:id])
    assert_equal("png", params[:_format])
1024 1025 1026
  end

  def test_generate_with_default_action
1027
    set.draw do
1028
      match "/people", :controller => "people", :action => "index"
1029
      match "/people/list", :controller => "people", :action => "list"
1030 1031
    end

1032 1033 1034
    url = set.generate(:controller => "people", :action => "list")
    assert_equal "/people/list", url
  end
1035

1036
  def test_root_map
1037
    set.draw { root :to => 'people#index' }
1038

J
Joshua Peek 已提交
1039 1040 1041
    params = set.recognize_path("", :method => :get)
    assert_equal("people", params[:controller])
    assert_equal("index", params[:action])
1042 1043 1044
  end

  def test_namespace
1045
    set.draw do
1046

1047 1048
      namespace 'api' do
        match 'inventory' => 'products#inventory'
1049
      end
1050

1051 1052
    end

J
Joshua Peek 已提交
1053 1054 1055
    params = set.recognize_path("/api/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1056
  end
1057

1058
  def test_namespaced_root_map
1059 1060
    set.draw do
      namespace 'api' do
1061
        root :to => 'products#index'
1062 1063 1064
      end
    end

J
Joshua Peek 已提交
1065 1066 1067
    params = set.recognize_path("/api", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("index", params[:action])
1068
  end
1069

1070
  def test_namespace_with_path_prefix
1071
    set.draw do
1072
      scope :module => "api", :path => "prefix" do
1073
        match 'inventory' => 'products#inventory'
1074
      end
1075 1076
    end

J
Joshua Peek 已提交
1077 1078 1079
    params = set.recognize_path("/prefix/inventory", :method => :get)
    assert_equal("api/products", params[:controller])
    assert_equal("inventory", params[:action])
1080
  end
1081

1082
  def test_namespace_with_blank_path_prefix
1083
    set.draw do
1084
      scope :module => "api", :path => "" do
1085
        match 'inventory' => 'products#inventory'
1086 1087 1088
      end
    end

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

1094
  def test_generate_changes_controller_module
1095
    set.draw { match ':controller/:action/:id' }
1096 1097 1098 1099 1100
    current = { :controller => "bling/bloop", :action => "bap", :id => 9 }
    url = set.generate({:controller => "foo/bar", :action => "baz", :id => 7}, current)
    assert_equal "/foo/bar/baz/7", url
  end

1101
  # def test_id_is_not_impossibly_sticky
1102 1103 1104
  #   set.draw do
  #     match 'foo/:number' => 'people#index'
  #     match ':controller/:action/:id'
1105 1106 1107 1108 1109 1110
  #   end
  #
  #   url = set.generate({:controller => "people", :action => "index", :number => 3},
  #     {:controller => "people", :action => "index", :id => "21"})
  #   assert_equal "/foo/3", url
  # end
1111

1112
  def test_id_is_sticky_when_it_ought_to_be
1113 1114
    set.draw do
      match ':controller/:id/:action'
1115
    end
1116

1117 1118 1119
    url = set.generate({:action => "destroy"}, {:controller => "people", :action => "show", :id => "7"})
    assert_equal "/people/7/destroy", url
  end
1120

1121
  def test_use_static_path_when_possible
1122 1123 1124
    set.draw do
      match 'about' => "welcome#about"
      match ':controller/:action/:id'
1125 1126
    end

1127 1128 1129 1130
    url = set.generate({:controller => "welcome", :action => "about"},
      {:controller => "welcome", :action => "get", :id => "7"})
    assert_equal "/about", url
  end
1131

1132
  def test_generate
1133
    set.draw { match ':controller/:action/:id' }
1134

1135 1136 1137 1138 1139
    args = { :controller => "foo", :action => "bar", :id => "7", :x => "y" }
    assert_equal "/foo/bar/7?x=y", set.generate(args)
    assert_equal ["/foo/bar/7", [:x]], set.generate_extras(args)
    assert_equal [:x], set.extra_keys(args)
  end
1140

1141
  def test_generate_with_path_prefix
1142 1143 1144 1145 1146
    set.draw do
      scope "my" do
        match ':controller(/:action(/:id))'
      end
    end
1147

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

1152
  def test_generate_with_blank_path_prefix
1153 1154 1155 1156 1157
    set.draw do
      scope "" do
        match ':controller(/:action(/:id))'
      end
    end
1158 1159 1160 1161 1162

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

1163
  def test_named_routes_are_never_relative_to_modules
1164
    set.draw do
1165 1166 1167
      match "/connection/manage(/:action)" => 'connection/manage#index'
      match "/connection/connection" => "connection/connection#index"
      match '/connection' => 'connection#index', :as => 'family_connection'
1168
    end
1169

1170 1171 1172 1173 1174 1175 1176 1177
    url = set.generate({:controller => "connection"}, {:controller => 'connection/manage'})
    assert_equal "/connection/connection", url

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

  def test_action_left_off_when_id_is_recalled
1178
    set.draw do
1179
      match ':controller(/:action(/:id))'
1180
    end
1181 1182 1183
    assert_equal '/books', set.generate(
      {:controller => 'books', :action => 'index'},
      {:controller => 'books', :action => 'show', :id => '10'}
1184 1185
    )
  end
1186

1187
  def test_query_params_will_be_shown_when_recalled
1188 1189
    set.draw do
      match 'show_weblog/:parameter' => 'weblog#show'
1190
      match ':controller(/:action(/:id))'
1191
    end
1192
    assert_equal '/weblog/edit?parameter=1', set.generate(
1193
      {:action => 'edit', :parameter => 1},
1194
      {:controller => 'weblog', :action => 'show', :parameter => 1}
1195 1196
    )
  end
1197

1198
  def test_format_is_not_inherit
1199
    set.draw do
1200
      match '/posts(.:format)' => 'posts#index'
1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213
    end

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

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

1214
  def test_expiry_determination_should_consider_values_with_to_param
1215
    set.draw { match 'projects/:project_id/:controller/:action' }
1216
    assert_equal '/projects/1/weblog/show', set.generate(
1217
      {:action => 'show', :project_id => 1},
1218
      {:controller => 'weblog', :action => 'show', :project_id => '1'})
1219
  end
1220

1221
  def test_named_route_in_nested_resource
1222 1223 1224
    set.draw do
      resources :projects do
        match 'milestones' => 'milestones#index', :as => 'milestones'
1225 1226
      end
    end
1227

J
Joshua Peek 已提交
1228 1229 1230
    params = set.recognize_path("/projects/1/milestones", :method => :get)
    assert_equal("milestones", params[:controller])
    assert_equal("index", params[:action])
1231
  end
1232

1233 1234
  def test_setting_root_in_namespace_using_symbol
    assert_nothing_raised do
1235 1236
      set.draw do
        namespace :admin do
1237
          root :to => "home#index"
1238 1239 1240
        end
      end
    end
1241
  end
1242

1243 1244
  def test_setting_root_in_namespace_using_string
    assert_nothing_raised do
1245 1246
      set.draw do
        namespace 'admin' do
1247
          root :to => "home#index"
1248 1249 1250
        end
      end
    end
1251
  end
1252

1253
  def test_route_constraints_with_unsupported_regexp_options_must_error
1254
    assert_raise ArgumentError do
1255 1256 1257
      set.draw do
        match 'page/:name' => 'pages#show',
          :constraints => {:name => /(david|jamis)/m}
1258
      end
1259
    end
1260
  end
1261

1262
  def test_route_constraints_with_supported_options_must_not_error
1263
    assert_nothing_raised do
1264
      set.draw do
1265
        match 'page/:name' => 'pages#show',
1266
          :constraints => {:name => /(david|jamis)/i}
1267 1268
      end
    end
1269
    assert_nothing_raised do
1270 1271 1272
      set.draw do
        match 'page/:name' => 'pages#show',
          :constraints => {:name => / # Desperately overcommented regexp
1273 1274 1275 1276 1277 1278 1279
                                      ( #Either
                                       david #The Creator
                                      | #Or
                                        jamis #The Deployer
                                      )/x}
      end
    end
1280
  end
1281

1282
  def test_route_requirement_recognize_with_ignore_case
1283 1284 1285
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1286 1287
    end
    assert_equal({:controller => 'pages', :action => 'show', :name => 'jamis'}, set.recognize_path('/page/jamis'))
1288
    assert_raise ActionController::RoutingError do
1289
      set.recognize_path('/page/davidjamis')
1290
    end
1291 1292
    assert_equal({:controller => 'pages', :action => 'show', :name => 'DAVID'}, set.recognize_path('/page/DAVID'))
  end
1293

1294
  def test_route_requirement_generate_with_ignore_case
1295 1296 1297
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => /(david|jamis)/i}
1298
    end
1299

J
Jeremy Kemper 已提交
1300 1301 1302 1303
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
    assert_equal "/page/david", url
    assert_raise ActionController::RoutingError do
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
J
Jeremy Kemper 已提交
1304
    end
J
Jeremy Kemper 已提交
1305 1306
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
    assert_equal "/page/JAMIS", url
1307
  end
J
Jeremy Kemper 已提交
1308

1309
  def test_route_requirement_recognize_with_extended_syntax
1310 1311 1312
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => / # Desperately overcommented regexp
1313 1314 1315 1316 1317 1318 1319 1320
                                    ( #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'))
1321
    assert_raise ActionController::RoutingError do
1322 1323
      set.recognize_path('/page/david #The Creator')
    end
1324
    assert_raise ActionController::RoutingError do
1325
      set.recognize_path('/page/David')
1326 1327
    end
  end
1328

1329
  def test_route_requirement_generate_with_extended_syntax
1330 1331 1332
    set.draw do
      match 'page/:name' => 'pages#show',
        :constraints => {:name => / # Desperately overcommented regexp
1333 1334 1335 1336 1337 1338
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/x}
    end
1339

1340 1341 1342 1343 1344 1345 1346
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'david'})
    assert_equal "/page/david", url
    assert_raise ActionController::RoutingError do
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'davidjamis'})
    end
    assert_raise ActionController::RoutingError do
      url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
1347 1348
    end
  end
1349

1350
  def test_route_requirement_generate_with_xi_modifiers
1351
    set.draw do
1352
      match 'page/:name' => 'pages#show',
1353
        :constraints => {:name => / # Desperately overcommented regexp
1354 1355 1356 1357 1358
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1359
    end
1360

1361 1362
    url = set.generate({:controller => 'pages', :action => 'show', :name => 'JAMIS'})
    assert_equal "/page/JAMIS", url
1363
  end
1364

1365
  def test_route_requirement_recognize_with_xi_modifiers
1366
    set.draw do
1367
      match 'page/:name' => 'pages#show',
1368
        :constraints => {:name => / # Desperately overcommented regexp
1369 1370 1371 1372 1373
                                    ( #Either
                                     david #The Creator
                                    | #Or
                                      jamis #The Deployer
                                    )/xi}
1374
    end
1375 1376
    assert_equal({:controller => 'pages', :action => 'show', :name => 'JAMIS'}, set.recognize_path('/page/JAMIS'))
  end
1377 1378

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

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

J
Joshua Peek 已提交
1393 1394
    assert_equal '/', set.generate(:controller => 'foo')
    assert_equal '/hello', set.generate(:controller => 'bar')
1395

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

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

J
Joshua Peek 已提交
1405
    assert_equal '/cars/buy/1/2', set.generate(:controller => 'cars', :action => 'buy', :person => '1', :car => '2')
1406

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

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

J
Joshua Peek 已提交
1415
    assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list')
1416

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

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

J
Joshua Peek 已提交
1425 1426 1427 1428
    assert_equal '/books/list.rss', set.generate(:controller => 'books', :action => 'list', :format => 'rss')
    assert_equal '/books/list.xml', set.generate(:controller => 'books', :action => 'list', :format => 'xml')
    assert_equal '/books/list', set.generate(:controller => 'books', :action => 'list')
    assert_equal '/books', set.generate(:controller => 'books', :action => 'index')
1429

J
Joshua Peek 已提交
1430 1431 1432 1433
    assert_equal({:controller => "books", :action => "list", :format => "rss"}, set.recognize_path('/books/list.rss'))
    assert_equal({:controller => "books", :action => "list", :format => "xml"}, set.recognize_path('/books/list.xml'))
    assert_equal({:controller => "books", :action => "list"}, set.recognize_path('/books/list'))
    assert_equal({:controller => "books", :action => "index"}, set.recognize_path('/books'))
1434 1435 1436
  end

  def test_slashes_are_implied
1437 1438
    @set = nil
    set.draw { match("/:controller(/:action(/:id))") }
1439

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

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

  def test_default_route_recognition
J
Joshua Peek 已提交
1451 1452 1453
    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/')
1454 1455

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

    expected.delete :id
J
Joshua Peek 已提交
1459 1460
    assert_equal expected, default_route_set.recognize_path('/pages/show')
    assert_equal expected, default_route_set.recognize_path('/pages/show/')
1461 1462

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

    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
J
Joshua Peek 已提交
1467
    assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
  end

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

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

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

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

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

  def test_build_empty_query_string
J
Joshua Peek 已提交
1494
    assert_uri_equal '/foo', default_route_set.generate({:controller => 'foo'})
1495 1496 1497
  end

  def test_build_query_string_with_nil_value
J
Joshua Peek 已提交
1498
    assert_uri_equal '/foo', default_route_set.generate({:controller => 'foo', :x => nil})
1499 1500 1501
  end

  def test_simple_build_query_string
J
Joshua Peek 已提交
1502
    assert_uri_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => '1', :y => '2'})
1503 1504 1505
  end

  def test_convert_ints_build_query_string
J
Joshua Peek 已提交
1506
    assert_uri_equal '/foo?x=1&y=2', default_route_set.generate({:controller => 'foo', :x => 1, :y => 2})
1507 1508 1509
  end

  def test_escape_spaces_build_query_string
J
Joshua Peek 已提交
1510
    assert_uri_equal '/foo?x=hello+world&y=goodbye+world', default_route_set.generate({:controller => 'foo', :x => 'hello world', :y => 'goodbye world'})
1511 1512 1513
  end

  def test_expand_array_build_query_string
J
Joshua Peek 已提交
1514
    assert_uri_equal '/foo?x[]=1&x[]=2', default_route_set.generate({:controller => 'foo', :x => [1, 2]})
1515 1516 1517
  end

  def test_escape_spaces_build_query_string_selected_keys
J
Joshua Peek 已提交
1518
    assert_uri_equal '/foo?x=hello+world', default_route_set.generate({:controller => 'foo', :x => 'hello world'})
1519
  end
J
Joshua Peek 已提交
1520

1521
  def test_generate_with_default_params
1522 1523 1524 1525 1526 1527
    set.draw do
      match 'dummy/page/:page', :controller => 'dummy'
      match 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots'
      match 'ibocorp/:page', :controller => 'ibocorp',
                             :constraints => { :page => /\d+/ },
                             :defaults => { :page => 1 }
1528

1529
      match ':controller/:action/:id'
1530 1531
    end

1532
    assert_equal '/ibocorp', set.generate({:controller => 'ibocorp', :page => 1})
1533 1534
  end

1535
  def test_generate_with_optional_params_recalls_last_request
1536 1537
    set.draw do
      match "blog/", :controller => "blog", :action => "index"
1538

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

1545 1546 1547
      match "blog/show/:id", :controller => "blog", :action => "show", :id => /\d+/
      match "blog/:controller/:action/:id"
      match "*anything", :controller => "blog", :action => "unknown_request"
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
    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"))
    assert_equal({:controller => "blog", :action => "show_date", :year => "2004"}, set.recognize_path("/blog/2004"))
    assert_equal({:controller => "blog", :action => "show_date", :year => "2004", :month => "12"}, set.recognize_path("/blog/2004/12"))
    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"))
    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"))

    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)
    assert_equal("/blog/2006/07/25", set.generate({:day => 25}, last_request))
    assert_equal("/blog/2005", set.generate({:year => 2005}, last_request))
    assert_equal("/blog/show/123", set.generate({:action => "show" , :id => 123}, last_request))
1565
    assert_equal("/blog/2006", set.generate({:year => 2006}, last_request))
1566 1567 1568
    assert_equal("/blog/2006", set.generate({:year => 2006, :month => nil}, last_request))
  end

J
Joshua Peek 已提交
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
  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
1579
end
1580

1581 1582 1583
class RackMountIntegrationTests < ActiveSupport::TestCase
  Model = Struct.new(:to_param)

1584 1585 1586
  Mapping = lambda {
    namespace :admin do
      resources :users
1587 1588
    end

1589
    namespace 'api' do
1590
      root :controller => 'users#index'
1591 1592
    end

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

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

1605 1606
    resources :people
    match 'legacy/people', :controller => 'people', :action => 'index', :legacy => 'true'
1607

1608 1609 1610 1611 1612
    match 'symbols', :controller => :symbols, :action => :show, :name => :as_symbol
    match 'id_default/:id', :controller => 'foo', :action => 'id_default', :id => 1
    match 'get_or_post', :controller => 'foo', :action => 'get_or_post', :conditions => { :method => [:get, :post] }
    match 'optional/:optional', :controller => 'posts', :action => 'index'
    match 'projects/:project_id', :controller => 'project', :action => "index", :as => "project"
1613 1614 1615 1616 1617
    map.connect 'clients', :controller => 'projects', :action => 'index'

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

1625 1626
    match '', :controller => 'news', :format => nil
    match 'news(.:format)', :controller => 'news'
1627

1628 1629 1630 1631 1632 1633
    match 'comment/:id/:action', :controller => 'comments', :action => 'show'
    match 'ws/:controller/:action/:id', :ws => true
    match 'account/:action', :controller => :account, :action => :subscription
    match 'pages/:page_id/:controller/:action/:id'
    match ':controller/ping', :action => 'ping'
    match ':controller(/:action(/:id))'
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
  }

  def setup
    @routes = ActionController::Routing::RouteSet.new
    @routes.draw(&Mapping)
  end

  def test_add_route
    @routes.clear!

    assert_raise(ActionController::RoutingError) do
1645 1646
      @routes.draw do
        match 'file/*path' => 'content#show_file', :path => %w(fake default), :as => :path
1647
        match ':controller(/:action(/:id))'
1648 1649 1650 1651 1652 1653 1654 1655 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 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
      end
    end
  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))

    assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009'}, @routes.recognize_path('/blog/2009', :method => :get))
    assert_equal({:controller => 'posts', :action => 'show_date', :year => '2009', :month => '01'}, @routes.recognize_path('/blog/2009/01', :method => :get))
    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'))
    assert_equal({:controller => 'foo', :action => 'id_default', :id => '1'}, @routes.recognize_path('/id_default'))
    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'))

    assert_equal({:controller => 'news', :action => 'index', :format => nil}, @routes.recognize_path('/', :method => :get))
    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
    assert_equal '/admin/users', @routes.generate(:use_route => 'admin_users')
    assert_equal '/admin/users', @routes.generate(:controller => 'admin/users')
    assert_equal '/admin/users', @routes.generate(:controller => 'admin/users', :action => 'index')
    assert_equal '/admin/users', @routes.generate({:action => 'index'}, {:controller => 'admin/users'})
    assert_equal '/admin/users', @routes.generate({:controller => 'users', :action => 'index'}, {:controller => 'admin/accounts'})
    assert_equal '/people', @routes.generate({:controller => '/people', :action => 'index'}, {:controller => 'admin/accounts'})

    assert_equal '/admin/posts', @routes.generate({:controller => 'admin/posts'})
    assert_equal '/admin/posts/new', @routes.generate({:controller => 'admin/posts', :action => 'new'})

    assert_equal '/blog/2009', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009)
    assert_equal '/blog/2009/1', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009, :month => 1)
    assert_equal '/blog/2009/1/1', @routes.generate(:controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1)

    assert_equal '/archive/2010', @routes.generate(:controller => 'archive', :action => 'index', :year => '2010')
    assert_equal '/archive', @routes.generate(:controller => 'archive', :action => 'index')
    assert_equal '/archive?year=january', @routes.generate(:controller => 'archive', :action => 'index', :year => 'january')

    assert_equal '/people', @routes.generate(:use_route => 'people')
    assert_equal '/people', @routes.generate(:use_route => 'people', :controller => 'people', :action => 'index')
    assert_equal '/people.xml', @routes.generate(:use_route => 'people', :controller => 'people', :action => 'index', :format => 'xml')
    assert_equal '/people', @routes.generate({:use_route => 'people', :controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'index'})
    assert_equal '/people', @routes.generate(:controller => 'people')
    assert_equal '/people', @routes.generate(:controller => 'people', :action => 'index')
    assert_equal '/people', @routes.generate({:action => 'index'}, {:controller => 'people'})
    assert_equal '/people', @routes.generate({:action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'})
    assert_equal '/people', @routes.generate({:controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'})
    assert_equal '/people', @routes.generate({}, {:controller => 'people', :action => 'index'})
    assert_equal '/people/1', @routes.generate({:controller => 'people', :action => 'show'}, {:controller => 'people', :action => 'show', :id => '1'})
    assert_equal '/people/new', @routes.generate(:use_route => 'new_person')
    assert_equal '/people/new', @routes.generate(:controller => 'people', :action => 'new')
    assert_equal '/people/1', @routes.generate(:use_route => 'person', :id => '1')
    assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => '1')
    assert_equal '/people/1.xml', @routes.generate(:controller => 'people', :action => 'show', :id => '1', :format => 'xml')
    assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => 1)
    assert_equal '/people/1', @routes.generate(:controller => 'people', :action => 'show', :id => Model.new('1'))
    assert_equal '/people/1', @routes.generate({:action => 'show', :id => '1'}, {:controller => 'people', :action => 'index'})
    assert_equal '/people/1', @routes.generate({:action => 'show', :id => 1}, {:controller => 'people', :action => 'show', :id => '1'})
    # assert_equal '/people', @routes.generate({:controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'index', :id => '1'})
    assert_equal '/people', @routes.generate({:controller => 'people', :action => 'index'}, {:controller => 'people', :action => 'show', :id => '1'})
    assert_equal '/people/1', @routes.generate({}, {:controller => 'people', :action => 'show', :id => '1'})
    assert_equal '/people/1', @routes.generate({:controller => 'people', :action => 'show'}, {:controller => 'people', :action => 'index', :id => '1'})
    assert_equal '/people/1/edit', @routes.generate(:controller => 'people', :action => 'edit', :id => '1')
    assert_equal '/people/1/edit.xml', @routes.generate(:controller => 'people', :action => 'edit', :id => '1', :format => 'xml')
    assert_equal '/people/1/edit', @routes.generate(:use_route => 'edit_person', :id => '1')
    assert_equal '/people/1?legacy=true', @routes.generate(:controller => 'people', :action => 'show', :id => '1', :legacy => 'true')
    assert_equal '/people?legacy=true', @routes.generate(:controller => 'people', :action => 'index', :legacy => 'true')

    assert_equal '/id_default/2', @routes.generate(:controller => 'foo', :action => 'id_default', :id => '2')
    assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default', :id => '1')
    assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default', :id => 1)
    assert_equal '/id_default', @routes.generate(:controller => 'foo', :action => 'id_default')
    assert_equal '/optional/bar', @routes.generate(:controller => 'posts', :action => 'index', :optional => 'bar')
    assert_equal '/posts', @routes.generate(:controller => 'posts', :action => 'index')

    assert_equal '/project', @routes.generate({:controller => 'project', :action => 'index'})
    assert_equal '/projects/1', @routes.generate({:controller => 'project', :action => 'index', :project_id => '1'})
    assert_equal '/projects/1', @routes.generate({:controller => 'project', :action => 'index'}, {:project_id => '1'})
    assert_raise(ActionController::RoutingError) { @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index'}) }
    assert_equal '/projects/1', @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1'})
    assert_equal '/projects/1', @routes.generate({:use_route => 'project', :controller => 'project', :action => 'index'}, {:project_id => '1'})

    assert_equal '/clients', @routes.generate(:controller => 'projects', :action => 'index')
    assert_equal '/clients?project_id=1', @routes.generate(:controller => 'projects', :action => 'index', :project_id => '1')
    assert_equal '/clients', @routes.generate({:controller => 'projects', :action => 'index'}, {:project_id => '1'})
    assert_equal '/clients', @routes.generate({:action => 'index'}, {:controller => 'projects', :action => 'index', :project_id => '1'})

    assert_equal '/comment/20', @routes.generate({:id => 20}, {:controller => 'comments', :action => 'show'})
    assert_equal '/comment/20', @routes.generate(:controller => 'comments', :id => 20, :action => 'show')
    assert_equal '/comments/boo', @routes.generate(:controller => 'comments', :action => 'boo')

    assert_equal '/ws/posts/show/1', @routes.generate(:controller => 'posts', :action => 'show', :id => '1', :ws => true)
    assert_equal '/ws/posts', @routes.generate(:controller => 'posts', :action => 'index', :ws => true)

    assert_equal '/account', @routes.generate(:controller => 'account', :action => 'subscription')
    assert_equal '/account/billing', @routes.generate(:controller => 'account', :action => 'billing')

    assert_equal '/pages/1/notes/show/1', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'show', :id => '1')
    assert_equal '/pages/1/notes/list', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'list')
    assert_equal '/pages/1/notes', @routes.generate(:page_id => '1', :controller => 'notes', :action => 'index')
    assert_equal '/pages/1/notes', @routes.generate(:page_id => '1', :controller => 'notes')
    assert_equal '/notes', @routes.generate(:page_id => nil, :controller => 'notes')
    assert_equal '/notes', @routes.generate(:controller => 'notes')
    assert_equal '/notes/print', @routes.generate(:controller => 'notes', :action => 'print')
    assert_equal '/notes/print', @routes.generate({}, {:controller => 'notes', :action => 'print'})

    assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1'})
    assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1', :foo => 'bar'})
    assert_equal '/notes/index/1', @routes.generate({:controller => 'notes'}, {:controller => 'notes', :id => '1'})
    assert_equal '/notes/index/1', @routes.generate({:action => 'index'}, {:controller => 'notes', :id => '1'})
    assert_equal '/notes/index/1', @routes.generate({}, {:controller => 'notes', :id => '1'})
    assert_equal '/notes/show/1', @routes.generate({}, {:controller => 'notes', :action => 'show', :id => '1'})
    assert_equal '/notes/index/1', @routes.generate({:controller => 'notes', :id => '1'}, {:foo => 'bar'})
    assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'notes', :action => 'show', :id => '1'})
    assert_equal '/notes/list', @routes.generate({:action => 'list'}, {:controller => 'notes', :action => 'show', :id => '1'})

    assert_equal '/posts/ping', @routes.generate(:controller => 'posts', :action => 'ping')
    assert_equal '/posts/show/1', @routes.generate(:controller => 'posts', :action => 'show', :id => '1')
    assert_equal '/posts', @routes.generate(:controller => 'posts')
    assert_equal '/posts', @routes.generate(:controller => 'posts', :action => 'index')
    assert_equal '/posts', @routes.generate({:controller => 'posts'}, {:controller => 'posts', :action => 'index'})
    assert_equal '/posts/create', @routes.generate({:action => 'create'}, {:controller => 'posts'})
    assert_equal '/posts?foo=bar', @routes.generate(:controller => 'posts', :foo => 'bar')
J
Joshua Peek 已提交
1831
    assert_equal '/posts?foo[]=bar&foo[]=baz', @routes.generate(:controller => 'posts', :foo => ['bar', 'baz'])
1832
    assert_equal '/posts?page=2', @routes.generate(:controller => 'posts', :page => 2)
J
Joshua Peek 已提交
1833
    assert_equal '/posts?q[foo][a]=b', @routes.generate(:controller => 'posts', :q => { :foo => { :a => 'b'}})
1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889

    assert_equal '/', @routes.generate(:controller => 'news', :action => 'index')
    assert_equal '/', @routes.generate(:controller => 'news', :action => 'index', :format => nil)
    assert_equal '/news.rss', @routes.generate(:controller => 'news', :action => 'index', :format => 'rss')


    assert_raise(ActionController::RoutingError) { @routes.generate({:action => 'index'}) }
  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