routing_test.rb 87.2 KB
Newer Older
1
# encoding: UTF-8
2
require 'erb'
3 4 5 6 7 8 9 10 11 12 13 14 15 16
require 'abstract_unit'
require 'controller/fake_controllers'

class TestRoutingMapper < ActionDispatch::IntegrationTest
  SprocketsApp = lambda { |env|
    [200, {"Content-Type" => "text/html"}, ["javascripts"]]
  }

  class IpRestrictor
    def self.matches?(request)
      request.ip =~ /192\.168\.1\.1\d\d/
    end
  end

17 18 19 20 21 22
  class YoutubeFavoritesRedirector
    def self.call(params, request)
      "http://www.youtube.com/watch?v=#{params[:youtube_id]}"
    end
  end

23 24
  stub_controllers do |routes|
    Routes = routes
25
    Routes.draw do
26
      default_url_options :host => "rubyonrails.org"
27
      resources_path_names :correlation_indexes => "info_about_correlation_indexes"
28

29
      controller :sessions do
30
        get  'login' => :new
31
        post 'login' => :create
32
        delete 'logout' => :destroy
33
      end
34

35 36
      resource :session do
        get :create
37
        post :reset
38 39

        resource :info
40 41 42 43

        member do
          get :crush
        end
44 45
      end

46 47 48 49
      scope "bookmark", :controller => "bookmarks", :as => :bookmark do
        get  :new, :path => "build"
        post :create, :path => "create", :as => ""
        put  :update
50 51 52 53 54 55 56
        get  :remove, :action => :destroy, :as => :remove
      end

      scope "pagemark", :controller => "pagemarks", :as => :pagemark do
        get  "new", :path => "build"
        post "create", :as => ""
        put  "update"
57 58 59
        get  "remove", :action => :destroy, :as => :remove
      end

60 61 62
      get 'account/logout' => redirect("/logout"), :as => :logout_redirect
      get 'account/login', :to => redirect("/login")
      get 'secure', :to => redirect("/secure/login")
63

64
      get 'mobile', :to => redirect(:subdomain => 'mobile')
65 66
      get 'documentation', :to => redirect(:domain => 'example-documentation.com', :path => '')
      get 'new_documentation', :to => redirect(:path => '/documentation/new')
67
      get 'super_new_documentation', :to => redirect(:host => 'super-docs.com')
68

69 70 71
      get 'stores/:name',        :to => redirect(:subdomain => 'stores', :path => '/%{name}')
      get 'stores/:name(*rest)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{rest}')

72
      get 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector)
73

74
      constraints(lambda { |req| true }) do
75
        get 'account/overview'
76 77
      end

78 79
      get '/account/nested/overview'
      get 'sign_in' => "sessions#new"
80

81 82 83
      get 'account/modulo/:name', :to => redirect("/%{name}s")
      get 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" }
      get 'account/proc_req' => redirect {|params, req| "/#{req.method}" }
84

85
      get 'account/google' => redirect('http://www.google.com/', :status => 302)
86

87
      match 'openid/login', :via => [:get, :post], :to => "openid#login"
88

89
      controller(:global) do
90
        get   'global/hide_notice'
91 92 93
        get 'global/export',      :to => :export, :as => :export_request
        get '/export/:id/:file',  :to => :export, :as => :export_download, :constraints => { :file => /.*/ }
        get 'global/:action'
94 95
      end

96
      get "/local/:action", :controller => "local"
97

98 99
      get "/projects/status(.:format)"
      get "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] }
100

101
      constraints(:ip => /192\.168\.1\.\d\d\d/) do
102
        get 'admin' => "queenbee#index"
103 104
      end

105
      constraints ::TestRoutingMapper::IpRestrictor do
106
        get 'admin/accounts' => "queenbee#accounts"
107 108
      end

109 110
      get 'admin/passwords' => "queenbee#passwords", :constraints => ::TestRoutingMapper::IpRestrictor

111
      scope 'pt', :as => 'pt' do
112 113
        resources :projects, :path_names => { :edit => 'editar', :new => 'novo' }, :path => 'projetos' do
          post :preview, :on => :new
114 115
          put :close, :on => :member, :path => 'fechar'
          get :open, :on => :new, :path => 'abrir'
116
        end
117
        resource  :admin, :path_names => { :new => 'novo', :activate => 'ativar' }, :path => 'administrador' do
118
          post :preview, :on => :new
119
          put :activate, :on => :member
120 121 122 123 124 125
        end
        resources :products, :path_names => { :new => 'novo' } do
          new do
            post :preview
          end
        end
126 127
      end

128 129
      resources :projects, :controller => :project do
        resources :involvements, :attachments
130
        get :correlation_indexes, :on => :collection
131 132 133

        resources :participants do
          put :update_all, :on => :collection
134 135
        end

136 137
        resources :companies do
          resources :people
138
          resource  :avatar, :controller => :avatar
139 140
        end

141
        resources :images, :as => :funny_images do
142 143 144
          post :revise, :on => :member
        end

145 146 147 148
        resource :manager, :as => :super_manager do
          post :fire
        end

149
        resources :people do
150
          nested do
151
            scope "/:access_token" do
152 153
              resource :avatar
            end
154 155 156
          end

          member do
157
            get  'some_path_with_name'
158 159 160
            put  :accessible_projects
            post :resend, :generate_new_password
          end
161 162
        end

163
        resources :posts do
164
          get  :archive, :toggle_view, :on => :collection
165
          post :preview, :on => :member
166

167
          resource :subscription
168

169 170 171
          resources :comments do
            post :preview, :on => :collection
          end
172
        end
173 174

        post 'new', :action => 'new', :on => :collection, :as => :new
175 176
      end

177
      resources :replies do
178 179 180 181 182
        collection do
          get 'page/:page' => 'replies#index', :page => %r{\d+}
          get ':page' => 'replies#index', :page => %r{\d+}
        end

183 184 185 186
        new do
          post :preview
        end

187 188 189 190 191 192
        member do
          put :answer, :to => :mark_as_answer
          delete :answer, :to => :unmark_as_answer
        end
      end

193
      resources :posts, :only => [:index, :show] do
194 195 196
        namespace :admin do
          root :to => "index#index"
        end
197 198 199
        resources :comments, :except => :destroy do
          get "views" => "comments#views", :as => :views
        end
200
      end
201

202 203 204 205 206 207
      resource  :past, :only => :destroy
      resource  :present, :only => :update
      resource  :future, :only => :create
      resources :relationships, :only => [:create, :destroy]
      resources :friendships,   :only => [:update]

208 209 210 211 212 213 214 215 216
      shallow do
        namespace :api do
          resources :teams do
            resources :players
            resource :captain
          end
        end
      end

217 218 219 220 221 222 223 224
      scope '/hello' do
        shallow do
          resources :notes do
            resources :trackbacks
          end
        end
      end

225 226 227 228 229 230 231 232 233 234 235
      resources :threads, :shallow => true do
        resource :owner
        resources :messages do
          resources :comments do
            member do
              post :preview
            end
          end
        end
      end

236 237 238
      resources :sheep do
        get "_it", :on => :member
      end
239

240 241
      resources :clients do
        namespace :google do
242 243 244 245 246
          resource :account do
            namespace :secret do
              resource :info
            end
          end
247 248 249
        end
      end

250
      resources :customers do
251 252 253
        get :recent, :on => :collection
        get "profile", :on => :member
        get "secret/profile" => "customers#secret", :on => :member
254
        post "preview" => "customers#preview", :as => :another_preview, :on => :new
255
        resource :avatar do
256
          get "thumbnail" => "avatars#thumbnail", :as => :thumbnail, :on => :member
257 258
        end
        resources :invoices do
259
          get "outstanding" => "invoices#outstanding", :on => :collection
260 261 262
          get "overdue", :to => :overdue, :on => :collection
          get "print" => "invoices#print", :as => :print, :on => :member
          post "preview" => "invoices#preview", :as => :preview, :on => :new
263
          get "aged/:months", :on => :collection, :action => :aged, :as => :aged
264 265 266 267 268
        end
        resources :notes, :shallow => true do
          get "preview" => "notes#preview", :as => :preview, :on => :new
          get "print" => "notes#print", :as => :print, :on => :member
        end
269 270 271
        get "inactive", :on => :collection
        post "deactivate", :on => :member
        get "old", :on => :collection, :as => :stale
272
        get "export"
273 274 275 276 277 278 279 280
      end

      namespace :api do
        resources :customers do
          get "recent" => "customers#recent", :as => :recent, :on => :collection
          get "profile" => "customers#profile", :as => :profile, :on => :member
          post "preview" => "customers#preview", :as => :preview, :on => :new
        end
281 282 283
        scope(':version', :version => /.+/) do
          resources :users, :id => /.+?/, :format => /json|xml/
        end
284 285

        get "products/list"
286 287
      end

288
      get 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
289

290 291
      get 'people/:id/update', :to => 'people#update', :as => :update_person
      get '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
292

293
      # misc
294
      get 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article
295

296
      # default params
297 298
      get 'inline_pages/(:id)', :to => 'pages#show', :id => 'home'
      get 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' }
299
      defaults :id => 'home' do
300
        get 'scoped_pages/(:id)', :to => 'pages#show'
301 302
      end

303
      namespace :account do
304 305 306
        get 'shorthand'
        get 'description', :to => :description, :as => "description"
        get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback
307
        resource :subscription, :credit, :credit_card
308

309 310
        root :to => "account#index"

311 312 313
        namespace :admin do
          resource :subscription
        end
314
      end
315

316
      namespace :forum do
317
        resources :products, :path => '' do
318 319 320 321
          resources :questions
        end
      end

322 323 324 325
      namespace :users, :path => 'usuarios' do
        root :to => 'home#index'
      end

326
      controller :articles do
327
        scope '/articles', :as => 'article' do
J
Joshua Peek 已提交
328
          scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
329
            get '/:id', :to => :with_id, :as => ""
330
          end
331 332 333
        end
      end

334 335 336
      scope ':access_token', :constraints => { :access_token => /\w{5,5}/ } do
        resources :rooms
      end
337

338
      get '/info' => 'projects#info', :as => 'info'
339 340

      namespace :admin do
341
        scope '(:locale)', :locale => /en|pl/ do
342 343 344 345
          resources :descriptions
        end
      end

346
      scope '(:locale)', :locale => /en|pl/ do
347
        get "registrations/new"
348 349 350
        resources :descriptions
        root :to => 'projects#index'
      end
351

352 353 354 355 356 357 358
      scope :only => [:index, :show] do
        resources :products, :constraints => { :id => /\d{4}/ } do
          root :to => "products#root"
          get :favorite, :on => :collection
          resources :images
        end
        resource :account
359 360 361
      end

      resource :dashboard, :constraints => { :ip => /192\.168\.1\.\d{1,3}/ }
362

363
      resource :token, :module => :api
364 365 366 367
      scope :module => :api do
        resources :errors, :shallow => true do
          resources :notices
        end
368 369
      end

370
      scope :path => 'api' do
371
        resource :me
372
        get '/' => 'mes#index'
373 374 375 376 377 378 379 380
        scope :v2 do
          resource :me, as: 'v2_me'
          get '/' => 'mes#index'
        end

        scope :v3, :admin do
          resource :me, as: 'v3_me'
        end
381
      end
382

383 384 385 386
      get "(/:username)/followers" => "followers#index"
      get "/groups(/user/:username)" => "groups#index"
      get "(/user/:username)/photos" => "photos#index"

387 388 389 390 391 392
      scope '(groups)' do
        scope '(discussions)' do
          resources :messages
        end
      end

393
      get "whatever/:controller(/:action(/:id))", :id => /\d+/
394 395 396 397 398 399 400 401

      resource :profile do
        get :settings

        new do
          post :preview
        end
      end
402

403 404
      resources :content

405 406 407 408 409 410 411 412
      namespace :transport do
        resources :taxis
      end

      namespace :medical do
        resource :taxis
      end

413 414 415 416
      scope :constraints => { :id => /\d+/ } do
        get '/tickets', :to => 'tickets#index', :as => :tickets
      end

417 418 419 420 421 422 423
      scope :constraints => { :id => /\d{4}/ } do
        resources :movies do
          resources :reviews
          resource :trailer
        end
      end

424 425
      namespace :private do
        root :to => redirect('/private/index')
426
        get "index", :to => 'private#index'
427 428
      end

429 430 431 432 433 434
      scope :only => [:index, :show] do
        namespace :only do
          resources :clubs do
            resources :players
            resource  :chairman
          end
435 436 437
        end
      end

438 439 440 441 442 443 444 445 446
      scope :except => [:new, :create, :edit, :update, :destroy] do
        namespace :except do
          resources :clubs do
            resources :players
            resource  :chairman
          end
        end
      end

447 448 449 450 451 452
      namespace :wiki do
        resources :articles, :id => /[^\/]+/ do
          resources :comments, :only => [:create, :new]
        end
      end

453 454 455
      resources :wiki_pages, :path => :pages
      resource :wiki_account, :path => :my_account

456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
      scope :only => :show do
        namespace :only do
          resources :sectors, :only => :index do
            resources :companies do
              scope :only => :index do
                resources :divisions
              end
              scope :except => [:show, :update, :destroy] do
                resources :departments
              end
            end
            resource  :leader
            resources :managers, :except => [:show, :update, :destroy]
          end
        end
      end

      scope :except => :index do
        namespace :except do
          resources :sectors, :except => [:show, :update, :destroy] do
            resources :companies do
              scope :except => [:show, :update, :destroy] do
                resources :divisions
              end
              scope :only => :index do
                resources :departments
              end
            end
            resource  :leader
            resources :managers, :only => :index
486 487 488 489
          end
        end
      end

490 491 492 493
      resources :sections, :id => /.+/ do
        get :preview, :on => :member
      end

494
      resources :profiles, :param => :username, :username => /[a-z]+/ do
495 496 497 498
        get :details, :on => :member
        resources :messages
      end

499 500 501 502 503 504
      resources :orders do
        constraints :download => /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/ do
          resources :downloads, :param => :download, :shallow => true
        end
      end

505 506 507 508 509 510 511 512 513
      scope :as => "routes" do
        get "/c/:id", :as => :collision, :to => "collision#show"
        get "/collision", :to => "collision#show"
        get "/no_collision", :to => "collision#show", :as => nil

        get "/fc/:id", :as => :forced_collision, :to => "forced_collision#show"
        get "/forced_collision", :as => :forced_collision, :to => "forced_collision#show"
      end

514
      get '/purchases/:token/:filename',
515 516 517 518 519
        :to => 'purchases#fetch',
        :token => /[[:alnum:]]{10}/,
        :filename => /(.+)/,
        :as => :purchase

520 521 522 523
      resources :lists, :id => /([A-Za-z0-9]{25})|default/ do
        resources :todos, :id => /\d+/
      end

524
      scope '/countries/:country', :constraints => lambda { |params, req| %w(all France).include?(params[:country]) } do
525 526
        get '/',       :to => 'countries#index'
        get '/cities', :to => 'countries#cities'
527 528
      end

529
      get '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' }
530

531
      get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
532 533

      scope '/italians' do
534 535 536
        get '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor
        get '/sculptors', :to => 'italians#sculptors'
        get '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/}
537
      end
538 539 540
    end
  end

541
  class TestAltApp < ActionDispatch::IntegrationTest
542 543 544 545 546 547 548 549 550 551 552 553 554
    class AltRequest
      def initialize(env)
        @env = env
      end

      def path_info
        "/"
      end

      def request_method
        "GET"
      end

555 556 557 558
      def ip
        "127.0.0.1"
      end

559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
      def x_header
        @env["HTTP_X_HEADER"] || ""
      end
    end

    class XHeader
      def call(env)
        [200, {"Content-Type" => "text/html"}, ["XHeader"]]
      end
    end

    class AltApp
      def call(env)
        [200, {"Content-Type" => "text/html"}, ["Alternative App"]]
      end
    end

    AltRoutes = ActionDispatch::Routing::RouteSet.new(AltRequest)
    AltRoutes.draw do
578 579
      get "/" => TestRoutingMapper::TestAltApp::XHeader.new, :constraints => {:x_header => /HEADER/}
      get "/" => TestRoutingMapper::TestAltApp::AltApp.new
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
    end

    def app
      AltRoutes
    end

    def test_alt_request_without_header
      get "/"
      assert_equal "Alternative App", @response.body
    end

    def test_alt_request_with_matched_header
      get "/", {}, "HTTP_X_HEADER" => "HEADER"
      assert_equal "XHeader", @response.body
    end

    def test_alt_request_with_unmatched_header
      get "/", {}, "HTTP_X_HEADER" => "NON_MATCH"
      assert_equal "Alternative App", @response.body
    end
  end

602 603 604 605
  def app
    Routes
  end

606
  include Routes.url_helpers
C
Carlhuda 已提交
607

608
  def test_logout
609 610
    delete '/logout'
    assert_equal 'sessions#destroy', @response.body
611

612 613
    assert_equal '/logout', logout_path
    assert_equal '/logout', url_for(:controller => 'sessions', :action => 'destroy', :only_path => true)
614 615 616
  end

  def test_login
617 618 619
    get '/login'
    assert_equal 'sessions#new', @response.body
    assert_equal '/login', login_path
620

621 622
    post '/login'
    assert_equal 'sessions#create', @response.body
623

624 625
    assert_equal '/login', url_for(:controller => 'sessions', :action => 'create', :only_path => true)
    assert_equal '/login', url_for(:controller => 'sessions', :action => 'new', :only_path => true)
626

627 628
    assert_equal 'http://rubyonrails.org/login', Routes.url_for(:controller => 'sessions', :action => 'create')
    assert_equal 'http://rubyonrails.org/login', Routes.url_helpers.login_url
629 630 631
  end

  def test_login_redirect
632 633
    get '/account/login'
    verify_redirect 'http://www.example.com/login'
634 635
  end

636
  def test_logout_redirect_without_to
637 638 639
    assert_equal '/account/logout', logout_redirect_path
    get '/account/logout'
    verify_redirect 'http://www.example.com/logout'
640 641
  end

642
  def test_namespace_redirect
643 644
    get '/private'
    verify_redirect 'http://www.example.com/private/index'
645 646
  end

647
  def test_namespace_with_controller_segment
648 649 650 651
    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw do
          namespace :admin do
652
            get '/:controller(/:action(/:id(.:format)))'
653 654 655
          end
        end
      end
656 657 658
    end
  end

659
  def test_session_singleton_resource
660 661 662
    get '/session'
    assert_equal 'sessions#create', @response.body
    assert_equal '/session', session_path
663

664 665
    post '/session'
    assert_equal 'sessions#create', @response.body
666

667 668
    put '/session'
    assert_equal 'sessions#update', @response.body
669

670 671
    delete '/session'
    assert_equal 'sessions#destroy', @response.body
672

673 674 675
    get '/session/new'
    assert_equal 'sessions#new', @response.body
    assert_equal '/session/new', new_session_path
676

677 678 679
    get '/session/edit'
    assert_equal 'sessions#edit', @response.body
    assert_equal '/session/edit', edit_session_path
680

681 682 683
    post '/session/reset'
    assert_equal 'sessions#reset', @response.body
    assert_equal '/session/reset', reset_session_path
684 685
  end

686
  def test_session_info_nested_singleton_resource
687 688 689
    get '/session/info'
    assert_equal 'infos#show', @response.body
    assert_equal '/session/info', session_info_path
690 691
  end

692
  def test_member_on_resource
693 694 695
    get '/session/crush'
    assert_equal 'sessions#crush', @response.body
    assert_equal '/session/crush', crush_session_path
696 697
  end

698
  def test_redirect_modulo
699 700
    get '/account/modulo/name'
    verify_redirect 'http://www.example.com/names'
701 702 703
  end

  def test_redirect_proc
704 705
    get '/account/proc/person'
    verify_redirect 'http://www.example.com/people'
706 707
  end

708
  def test_redirect_proc_with_request
709 710
    get '/account/proc_req'
    verify_redirect 'http://www.example.com/GET'
711 712
  end

713
  def test_redirect_hash_with_subdomain
714 715
    get '/mobile'
    verify_redirect 'http://mobile.example.com/mobile'
716 717
  end

718 719 720 721 722 723 724 725 726 727
  def test_redirect_hash_with_domain_and_path
    get '/documentation'
    verify_redirect 'http://www.example-documentation.com'
  end

  def test_redirect_hash_with_path
    get '/new_documentation'
    verify_redirect 'http://www.example.com/documentation/new'
  end

728
  def test_redirect_hash_with_host
729 730
    get '/super_new_documentation?section=top'
    verify_redirect 'http://super-docs.com/super_new_documentation?section=top'
731 732
  end

733 734 735 736 737 738 739 740 741 742
  def test_redirect_hash_path_substitution
    get '/stores/iernest'
    verify_redirect 'http://stores.example.com/iernest'
  end

  def test_redirect_hash_path_substitution_with_catch_all
    get '/stores/iernest/products'
    verify_redirect 'http://stores.example.com/iernest/products'
  end

743
  def test_redirect_class
744 745
    get '/youtube_favorites/oHg5SJYRHA0/rick-rolld'
    verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0'
746 747
  end

748
  def test_openid
749 750
    get '/openid/login'
    assert_equal 'openid#login', @response.body
751

752 753
    post '/openid/login'
    assert_equal 'openid#login', @response.body
754 755
  end

756
  def test_bookmarks
757 758 759 760 761 762 763 764 765 766 767 768 769 770 771
    get '/bookmark/build'
    assert_equal 'bookmarks#new', @response.body
    assert_equal '/bookmark/build', bookmark_new_path

    post '/bookmark/create'
    assert_equal 'bookmarks#create', @response.body
    assert_equal '/bookmark/create', bookmark_path

    put '/bookmark/update'
    assert_equal 'bookmarks#update', @response.body
    assert_equal '/bookmark/update', bookmark_update_path

    get '/bookmark/remove'
    assert_equal 'bookmarks#destroy', @response.body
    assert_equal '/bookmark/remove', bookmark_remove_path
772 773
  end

774
  def test_pagemarks
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    get '/pagemark/build'
    assert_equal 'pagemarks#new', @response.body
    assert_equal '/pagemark/build', pagemark_new_path

    post '/pagemark/create'
    assert_equal 'pagemarks#create', @response.body
    assert_equal '/pagemark/create', pagemark_path

    put '/pagemark/update'
    assert_equal 'pagemarks#update', @response.body
    assert_equal '/pagemark/update', pagemark_update_path

    get '/pagemark/remove'
    assert_equal 'pagemarks#destroy', @response.body
    assert_equal '/pagemark/remove', pagemark_remove_path
790 791
  end

J
Joshua Peek 已提交
792
  def test_admin
793 794
    get '/admin', {}, {'REMOTE_ADDR' => '192.168.1.100'}
    assert_equal 'queenbee#index', @response.body
J
Joshua Peek 已提交
795

796 797
    get '/admin', {}, {'REMOTE_ADDR' => '10.0.0.100'}
    assert_equal 'pass', @response.headers['X-Cascade']
J
Joshua Peek 已提交
798

799 800
    get '/admin/accounts', {}, {'REMOTE_ADDR' => '192.168.1.100'}
    assert_equal 'queenbee#accounts', @response.body
J
Joshua Peek 已提交
801

802 803
    get '/admin/accounts', {}, {'REMOTE_ADDR' => '10.0.0.100'}
    assert_equal 'pass', @response.headers['X-Cascade']
804

805 806
    get '/admin/passwords', {}, {'REMOTE_ADDR' => '192.168.1.100'}
    assert_equal 'queenbee#passwords', @response.body
807

808 809
    get '/admin/passwords', {}, {'REMOTE_ADDR' => '10.0.0.100'}
    assert_equal 'pass', @response.headers['X-Cascade']
J
Joshua Peek 已提交
810
  end
811 812

  def test_global
813 814
    get '/global/dashboard'
    assert_equal 'global#dashboard', @response.body
815

816 817
    get '/global/export'
    assert_equal 'global#export', @response.body
818

819 820
    get '/global/hide_notice'
    assert_equal 'global#hide_notice', @response.body
821

822 823
    get '/export/123/foo.txt'
    assert_equal 'global#export', @response.body
824

825 826 827
    assert_equal '/global/export', export_request_path
    assert_equal '/global/hide_notice', global_hide_notice_path
    assert_equal '/export/123/foo.txt', export_download_path(:id => 123, :file => 'foo.txt')
828 829
  end

830
  def test_local
831 832
    get '/local/dashboard'
    assert_equal 'local#dashboard', @response.body
833 834
  end

835 836 837 838 839 840 841 842 843 844 845 846
  # tests the use of dup in url_for
  def test_url_for_with_no_side_effects
    # without dup, additional (and possibly unwanted) values will be present in the options (eg. :host)
    original_options = {:controller => 'projects', :action => 'status'}
    options = original_options.dup

    url_for options

    # verify that the options passed in have not changed from the original ones
    assert_equal original_options, options
  end

847 848 849 850
  def test_url_for_does_not_modify_controller
    controller = '/projects'
    options = {:controller => controller, :action => 'status', :only_path => true}
    url = url_for(options)
851

852 853
    assert_equal '/projects/status', url
    assert_equal '/projects', controller
854 855
  end

856 857 858 859 860 861 862 863 864 865 866
  # tests the arguments modification free version of define_hash_access
  def test_named_route_with_no_side_effects
    original_options = { :host => 'test.host' }
    options = original_options.dup

    profile_customer_url("customer_model", options)

    # verify that the options passed in have not changed from the original ones
    assert_equal original_options, options
  end

867
  def test_projects_status
868 869
    assert_equal '/projects/status', url_for(:controller => 'projects', :action => 'status', :only_path => true)
    assert_equal '/projects/status.json', url_for(:controller => 'projects', :action => 'status', :format => 'json', :only_path => true)
870 871
  end

872
  def test_projects
873 874 875
    get '/projects'
    assert_equal 'project#index', @response.body
    assert_equal '/projects', projects_path
876

877 878
    post '/projects'
    assert_equal 'project#create', @response.body
879

880 881 882
    get '/projects.xml'
    assert_equal 'project#index', @response.body
    assert_equal '/projects.xml', projects_path(:format => 'xml')
J
Joshua Peek 已提交
883

884 885 886
    get '/projects/new'
    assert_equal 'project#new', @response.body
    assert_equal '/projects/new', new_project_path
887

888 889 890
    get '/projects/new.xml'
    assert_equal 'project#new', @response.body
    assert_equal '/projects/new.xml', new_project_path(:format => 'xml')
J
Joshua Peek 已提交
891

892 893 894
    get '/projects/1'
    assert_equal 'project#show', @response.body
    assert_equal '/projects/1', project_path(:id => '1')
895

896 897 898
    get '/projects/1.xml'
    assert_equal 'project#show', @response.body
    assert_equal '/projects/1.xml', project_path(:id => '1', :format => 'xml')
J
Joshua Peek 已提交
899

900 901 902
    get '/projects/1/edit'
    assert_equal 'project#edit', @response.body
    assert_equal '/projects/1/edit', edit_project_path(:id => '1')
903 904
  end

905 906 907 908 909 910
  def test_projects_with_post_action_and_new_path_on_collection
    post '/projects/new'
    assert_equal "project#new", @response.body
    assert_equal "/projects/new", new_projects_path
  end

911
  def test_projects_involvements
912 913 914
    get '/projects/1/involvements'
    assert_equal 'involvements#index', @response.body
    assert_equal '/projects/1/involvements', project_involvements_path(:project_id => '1')
915

916 917 918
    get '/projects/1/involvements/new'
    assert_equal 'involvements#new', @response.body
    assert_equal '/projects/1/involvements/new', new_project_involvement_path(:project_id => '1')
919

920 921 922
    get '/projects/1/involvements/1'
    assert_equal 'involvements#show', @response.body
    assert_equal '/projects/1/involvements/1', project_involvement_path(:project_id => '1', :id => '1')
923

924 925
    put '/projects/1/involvements/1'
    assert_equal 'involvements#update', @response.body
926

927 928
    delete '/projects/1/involvements/1'
    assert_equal 'involvements#destroy', @response.body
929

930 931 932
    get '/projects/1/involvements/1/edit'
    assert_equal 'involvements#edit', @response.body
    assert_equal '/projects/1/involvements/1/edit', edit_project_involvement_path(:project_id => '1', :id => '1')
933 934 935
  end

  def test_projects_attachments
936 937 938
    get '/projects/1/attachments'
    assert_equal 'attachments#index', @response.body
    assert_equal '/projects/1/attachments', project_attachments_path(:project_id => '1')
939 940 941
  end

  def test_projects_participants
942 943 944 945 946 947 948
    get '/projects/1/participants'
    assert_equal 'participants#index', @response.body
    assert_equal '/projects/1/participants', project_participants_path(:project_id => '1')

    put '/projects/1/participants/update_all'
    assert_equal 'participants#update_all', @response.body
    assert_equal '/projects/1/participants/update_all', update_all_project_participants_path(:project_id => '1')
949 950 951
  end

  def test_projects_companies
952 953 954 955 956 957 958 959 960 961 962
    get '/projects/1/companies'
    assert_equal 'companies#index', @response.body
    assert_equal '/projects/1/companies', project_companies_path(:project_id => '1')

    get '/projects/1/companies/1/people'
    assert_equal 'people#index', @response.body
    assert_equal '/projects/1/companies/1/people', project_company_people_path(:project_id => '1', :company_id => '1')

    get '/projects/1/companies/1/avatar'
    assert_equal 'avatar#show', @response.body
    assert_equal '/projects/1/companies/1/avatar', project_company_avatar_path(:project_id => '1', :company_id => '1')
963 964
  end

965
  def test_project_manager
966 967 968 969 970 971 972 973 974 975 976
    get '/projects/1/manager'
    assert_equal 'managers#show', @response.body
    assert_equal '/projects/1/manager', project_super_manager_path(:project_id => '1')

    get '/projects/1/manager/new'
    assert_equal 'managers#new', @response.body
    assert_equal '/projects/1/manager/new', new_project_super_manager_path(:project_id => '1')

    post '/projects/1/manager/fire'
    assert_equal 'managers#fire', @response.body
    assert_equal '/projects/1/manager/fire', fire_project_super_manager_path(:project_id => '1')
977 978
  end

979
  def test_project_images
980 981 982 983 984 985 986 987 988 989 990
    get '/projects/1/images'
    assert_equal 'images#index', @response.body
    assert_equal '/projects/1/images', project_funny_images_path(:project_id => '1')

    get '/projects/1/images/new'
    assert_equal 'images#new', @response.body
    assert_equal '/projects/1/images/new', new_project_funny_image_path(:project_id => '1')

    post '/projects/1/images/1/revise'
    assert_equal 'images#revise', @response.body
    assert_equal '/projects/1/images/1/revise', revise_project_funny_image_path(:project_id => '1', :id => '1')
991 992 993
  end

  def test_projects_people
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    get '/projects/1/people'
    assert_equal 'people#index', @response.body
    assert_equal '/projects/1/people', project_people_path(:project_id => '1')

    get '/projects/1/people/1'
    assert_equal 'people#show', @response.body
    assert_equal '/projects/1/people/1', project_person_path(:project_id => '1', :id => '1')

    get '/projects/1/people/1/7a2dec8/avatar'
    assert_equal 'avatars#show', @response.body
    assert_equal '/projects/1/people/1/7a2dec8/avatar', project_person_avatar_path(:project_id => '1', :person_id => '1', :access_token => '7a2dec8')

    put '/projects/1/people/1/accessible_projects'
    assert_equal 'people#accessible_projects', @response.body
    assert_equal '/projects/1/people/1/accessible_projects', accessible_projects_project_person_path(:project_id => '1', :id => '1')

    post '/projects/1/people/1/resend'
    assert_equal 'people#resend', @response.body
    assert_equal '/projects/1/people/1/resend', resend_project_person_path(:project_id => '1', :id => '1')

    post '/projects/1/people/1/generate_new_password'
    assert_equal 'people#generate_new_password', @response.body
    assert_equal '/projects/1/people/1/generate_new_password', generate_new_password_project_person_path(:project_id => '1', :id => '1')
1017 1018
  end

1019
  def test_projects_with_resources_path_names
1020 1021 1022
    get '/projects/info_about_correlation_indexes'
    assert_equal 'project#correlation_indexes', @response.body
    assert_equal '/projects/info_about_correlation_indexes', correlation_indexes_projects_path
1023 1024
  end

1025
  def test_projects_posts
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
    get '/projects/1/posts'
    assert_equal 'posts#index', @response.body
    assert_equal '/projects/1/posts', project_posts_path(:project_id => '1')

    get '/projects/1/posts/archive'
    assert_equal 'posts#archive', @response.body
    assert_equal '/projects/1/posts/archive', archive_project_posts_path(:project_id => '1')

    get '/projects/1/posts/toggle_view'
    assert_equal 'posts#toggle_view', @response.body
    assert_equal '/projects/1/posts/toggle_view', toggle_view_project_posts_path(:project_id => '1')

    post '/projects/1/posts/1/preview'
    assert_equal 'posts#preview', @response.body
    assert_equal '/projects/1/posts/1/preview', preview_project_post_path(:project_id => '1', :id => '1')

    get '/projects/1/posts/1/subscription'
    assert_equal 'subscriptions#show', @response.body
    assert_equal '/projects/1/posts/1/subscription', project_post_subscription_path(:project_id => '1', :post_id => '1')

    get '/projects/1/posts/1/comments'
    assert_equal 'comments#index', @response.body
    assert_equal '/projects/1/posts/1/comments', project_post_comments_path(:project_id => '1', :post_id => '1')

    post '/projects/1/posts/1/comments/preview'
    assert_equal 'comments#preview', @response.body
    assert_equal '/projects/1/posts/1/comments/preview', preview_project_post_comments_path(:project_id => '1', :post_id => '1')
1053 1054
  end

1055
  def test_replies
1056 1057
    put '/replies/1/answer'
    assert_equal 'replies#mark_as_answer', @response.body
1058

1059 1060
    delete '/replies/1/answer'
    assert_equal 'replies#unmark_as_answer', @response.body
1061 1062
  end

1063
  def test_resource_routes_with_only_and_except
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    get '/posts'
    assert_equal 'posts#index', @response.body
    assert_equal '/posts', posts_path

    get '/posts/1'
    assert_equal 'posts#show', @response.body
    assert_equal '/posts/1', post_path(:id => 1)

    get '/posts/1/comments'
    assert_equal 'comments#index', @response.body
    assert_equal '/posts/1/comments', post_comments_path(:post_id => 1)

    post '/posts'
    assert_equal 'pass', @response.headers['X-Cascade']
    put '/posts/1'
    assert_equal 'pass', @response.headers['X-Cascade']
    delete '/posts/1'
    assert_equal 'pass', @response.headers['X-Cascade']
    delete '/posts/1/comments'
    assert_equal 'pass', @response.headers['X-Cascade']
1084
  end
1085

1086
  def test_resource_routes_only_create_update_destroy
1087 1088 1089 1090
    delete '/past'
    assert_equal 'pasts#destroy', @response.body
    assert_equal '/past', past_path

1091 1092 1093 1094
    patch '/present'
    assert_equal 'presents#update', @response.body
    assert_equal '/present', present_path

1095 1096 1097 1098 1099 1100 1101
    put '/present'
    assert_equal 'presents#update', @response.body
    assert_equal '/present', present_path

    post '/future'
    assert_equal 'futures#create', @response.body
    assert_equal '/future', future_path
1102 1103 1104
  end

  def test_resources_routes_only_create_update_destroy
1105 1106 1107 1108 1109 1110 1111 1112
    post '/relationships'
    assert_equal 'relationships#create', @response.body
    assert_equal '/relationships', relationships_path

    delete '/relationships/1'
    assert_equal 'relationships#destroy', @response.body
    assert_equal '/relationships/1', relationship_path(1)

1113 1114 1115 1116
    patch '/friendships/1'
    assert_equal 'friendships#update', @response.body
    assert_equal '/friendships/1', friendship_path(1)

1117 1118 1119
    put '/friendships/1'
    assert_equal 'friendships#update', @response.body
    assert_equal '/friendships/1', friendship_path(1)
1120 1121
  end

1122
  def test_resource_with_slugs_in_ids
1123 1124 1125
    get '/posts/rails-rocks'
    assert_equal 'posts#show', @response.body
    assert_equal '/posts/rails-rocks', post_path(:id => 'rails-rocks')
1126 1127
  end

1128
  def test_resources_for_uncountable_names
1129 1130 1131 1132 1133
    assert_equal '/sheep', sheep_index_path
    assert_equal '/sheep/1', sheep_path(1)
    assert_equal '/sheep/new', new_sheep_path
    assert_equal '/sheep/1/edit', edit_sheep_path(1)
    assert_equal '/sheep/1/_it', _it_sheep_path(1)
1134
  end
1135

1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
  def test_resource_does_not_modify_passed_options
    options = {:id => /.+?/, :format => /json|xml/}
    self.class.stub_controllers do |routes|
      routes.draw do
        resource :user, options
      end
    end
    assert_equal({:id => /.+?/, :format => /json|xml/}, options)
  end

  def test_resources_does_not_modify_passed_options
    options = {:id => /.+?/, :format => /json|xml/}
    self.class.stub_controllers do |routes|
      routes.draw do
        resources :users, options
      end
    end
    assert_equal({:id => /.+?/, :format => /json|xml/}, options)
  end

1156
  def test_path_names
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175
    get '/pt/projetos'
    assert_equal 'projects#index', @response.body
    assert_equal '/pt/projetos', pt_projects_path

    get '/pt/projetos/1/editar'
    assert_equal 'projects#edit', @response.body
    assert_equal '/pt/projetos/1/editar', edit_pt_project_path(1)

    get '/pt/administrador'
    assert_equal 'admins#show', @response.body
    assert_equal '/pt/administrador', pt_admin_path

    get '/pt/administrador/novo'
    assert_equal 'admins#new', @response.body
    assert_equal '/pt/administrador/novo', new_pt_admin_path

    put '/pt/administrador/ativar'
    assert_equal 'admins#activate', @response.body
    assert_equal '/pt/administrador/ativar', activate_pt_admin_path
1176 1177 1178
  end

  def test_path_option_override
1179 1180 1181 1182 1183 1184 1185
    get '/pt/projetos/novo/abrir'
    assert_equal 'projects#open', @response.body
    assert_equal '/pt/projetos/novo/abrir', open_new_pt_project_path

    put '/pt/projetos/1/fechar'
    assert_equal 'projects#close', @response.body
    assert_equal '/pt/projetos/1/fechar', close_pt_project_path(1)
1186 1187
  end

1188
  def test_sprockets
1189 1190
    get '/sprockets.js'
    assert_equal 'javascripts', @response.body
1191 1192 1193
  end

  def test_update_person_route
1194 1195
    get '/people/1/update'
    assert_equal 'people#update', @response.body
1196

1197
    assert_equal '/people/1/update', update_person_path(:id => 1)
1198 1199 1200
  end

  def test_update_project_person
1201 1202
    get '/projects/1/people/2/update'
    assert_equal 'people#update', @response.body
1203

1204
    assert_equal '/projects/1/people/2/update', update_project_person_path(:project_id => 1, :id => 2)
1205 1206
  end

1207
  def test_forum_products
1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
    get '/forum'
    assert_equal 'forum/products#index', @response.body
    assert_equal '/forum', forum_products_path

    get '/forum/basecamp'
    assert_equal 'forum/products#show', @response.body
    assert_equal '/forum/basecamp', forum_product_path(:id => 'basecamp')

    get '/forum/basecamp/questions'
    assert_equal 'forum/questions#index', @response.body
    assert_equal '/forum/basecamp/questions', forum_product_questions_path(:product_id => 'basecamp')

    get '/forum/basecamp/questions/1'
    assert_equal 'forum/questions#show', @response.body
    assert_equal '/forum/basecamp/questions/1', forum_product_question_path(:product_id => 'basecamp', :id => 1)
1223 1224
  end

1225
  def test_articles_perma
1226 1227
    get '/articles/2009/08/18/rails-3'
    assert_equal 'articles#show', @response.body
1228

1229
    assert_equal '/articles/2009/8/18/rails-3', article_path(:year => 2009, :month => 8, :day => 18, :title => 'rails-3')
1230 1231 1232
  end

  def test_account_namespace
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
    get '/account/subscription'
    assert_equal 'account/subscriptions#show', @response.body
    assert_equal '/account/subscription', account_subscription_path

    get '/account/credit'
    assert_equal 'account/credits#show', @response.body
    assert_equal '/account/credit', account_credit_path

    get '/account/credit_card'
    assert_equal 'account/credit_cards#show', @response.body
    assert_equal '/account/credit_card', account_credit_card_path
1244 1245
  end

1246
  def test_nested_namespace
1247 1248 1249
    get '/account/admin/subscription'
    assert_equal 'account/admin/subscriptions#show', @response.body
    assert_equal '/account/admin/subscription', account_admin_subscription_path
1250
  end
1251

1252
  def test_namespace_nested_in_resources
1253 1254 1255 1256 1257 1258 1259
    get '/clients/1/google/account'
    assert_equal '/clients/1/google/account', client_google_account_path(1)
    assert_equal 'google/accounts#show', @response.body

    get '/clients/1/google/account/secret/info'
    assert_equal '/clients/1/google/account/secret/info', client_google_account_secret_info_path(1)
    assert_equal 'google/secret/infos#show', @response.body
1260
  end
1261

1262
  def test_namespace_with_options
1263 1264 1265
    get '/usuarios'
    assert_equal '/usuarios', users_root_path
    assert_equal 'users/home#index', @response.body
1266 1267
  end

1268
  def test_articles_with_id
1269 1270
    get '/articles/rails/1'
    assert_equal 'articles#with_id', @response.body
1271

1272 1273
    get '/articles/123/1'
    assert_equal 'pass', @response.headers['X-Cascade']
1274

1275
    assert_equal '/articles/rails/1', article_with_title_path(:title => 'rails', :id => 1)
1276 1277 1278
  end

  def test_access_token_rooms
1279 1280
    get '/12345/rooms'
    assert_equal 'rooms#index', @response.body
1281

1282 1283
    get '/12345/rooms/1'
    assert_equal 'rooms#show', @response.body
1284

1285 1286
    get '/12345/rooms/1/edit'
    assert_equal 'rooms#edit', @response.body
1287
  end
J
Joshua Peek 已提交
1288

D
David Heinemeier Hansson 已提交
1289
  def test_root
1290 1291 1292
    assert_equal '/', root_path
    get '/'
    assert_equal 'projects#index', @response.body
D
David Heinemeier Hansson 已提交
1293
  end
1294

1295
  def test_index
1296 1297 1298
    assert_equal '/info', info_path
    get '/info'
    assert_equal 'projects#info', @response.body
1299
  end
D
David Heinemeier Hansson 已提交
1300

1301
  def test_match_shorthand_with_no_scope
1302 1303 1304
    assert_equal '/account/overview', account_overview_path
    get '/account/overview'
    assert_equal 'account#overview', @response.body
1305
  end
1306

1307
  def test_match_shorthand_inside_namespace
1308 1309 1310
    assert_equal '/account/shorthand', account_shorthand_path
    get '/account/shorthand'
    assert_equal 'account#shorthand', @response.body
1311 1312
  end

1313 1314 1315 1316 1317 1318
  def test_match_shorthand_inside_namespace_with_controller
    assert_equal '/api/products/list', api_products_list_path
    get '/api/products/list'
    assert_equal 'api/products#list', @response.body
  end

1319
  def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper
1320
    assert_equal '/replies', replies_path
1321 1322
  end

1323
  def test_scoped_controller_with_namespace_and_action
1324 1325 1326
    assert_equal '/account/twitter/callback', account_callback_path("twitter")
    get '/account/twitter/callback'
    assert_equal 'account/callbacks#twitter', @response.body
1327

1328 1329
    get '/account/whatever/callback'
    assert_equal 'Not Found', @response.body
1330 1331
  end

1332
  def test_convention_match_nested_and_with_leading_slash
1333 1334 1335
    assert_equal '/account/nested/overview', account_nested_overview_path
    get '/account/nested/overview'
    assert_equal 'account/nested#overview', @response.body
1336 1337
  end

1338
  def test_convention_with_explicit_end
1339 1340 1341
    get '/sign_in'
    assert_equal 'sessions#new', @response.body
    assert_equal '/sign_in', sign_in_path
1342 1343
  end

1344
  def test_redirect_with_complete_url_and_status
1345 1346
    get '/account/google'
    verify_redirect 'http://www.google.com/', 302
1347 1348
  end

1349 1350
  def test_redirect_with_port
    previous_host, self.host = self.host, 'www.example.com:3000'
1351 1352 1353

    get '/account/login'
    verify_redirect 'http://www.example.com:3000/login'
1354 1355 1356 1357
  ensure
    self.host = previous_host
  end

1358
  def test_normalize_namespaced_matches
1359
    assert_equal '/account/description', account_description_path
1360

1361 1362
    get '/account/description'
    assert_equal 'account#description', @response.body
1363 1364 1365
  end

  def test_namespaced_roots
1366 1367 1368
    assert_equal '/account', account_root_path
    get '/account'
    assert_equal 'account/account#index', @response.body
1369 1370
  end

1371
  def test_optional_scoped_root
1372 1373 1374
    assert_equal '/en', root_path("en")
    get '/en'
    assert_equal 'projects#index', @response.body
1375 1376
  end

1377
  def test_optional_scoped_path
1378 1379 1380 1381
    assert_equal '/en/descriptions', descriptions_path("en")
    assert_equal '/descriptions', descriptions_path(nil)
    assert_equal '/en/descriptions/1', description_path("en", 1)
    assert_equal '/descriptions/1', description_path(nil, 1)
1382

1383 1384
    get '/en/descriptions'
    assert_equal 'descriptions#index', @response.body
1385

1386 1387
    get '/descriptions'
    assert_equal 'descriptions#index', @response.body
1388

1389 1390
    get '/en/descriptions/1'
    assert_equal 'descriptions#show', @response.body
1391

1392 1393
    get '/descriptions/1'
    assert_equal 'descriptions#show', @response.body
1394 1395 1396
  end

  def test_nested_optional_scoped_path
1397 1398 1399 1400
    assert_equal '/admin/en/descriptions', admin_descriptions_path("en")
    assert_equal '/admin/descriptions', admin_descriptions_path(nil)
    assert_equal '/admin/en/descriptions/1', admin_description_path("en", 1)
    assert_equal '/admin/descriptions/1', admin_description_path(nil, 1)
1401

1402 1403
    get '/admin/en/descriptions'
    assert_equal 'admin/descriptions#index', @response.body
1404

1405 1406
    get '/admin/descriptions'
    assert_equal 'admin/descriptions#index', @response.body
1407

1408 1409
    get '/admin/en/descriptions/1'
    assert_equal 'admin/descriptions#show', @response.body
1410

1411 1412
    get '/admin/descriptions/1'
    assert_equal 'admin/descriptions#show', @response.body
1413 1414
  end

1415
  def test_nested_optional_path_shorthand
1416 1417
    get '/registrations/new'
    assert_nil @request.params[:locale]
1418

1419 1420
    get '/en/registrations/new'
    assert_equal 'en', @request.params[:locale]
1421 1422
  end

1423
  def test_default_params
1424 1425
    get '/inline_pages'
    assert_equal 'home', @request.params[:id]
1426

1427 1428
    get '/default_pages'
    assert_equal 'home', @request.params[:id]
1429

1430 1431
    get '/scoped_pages'
    assert_equal 'home', @request.params[:id]
1432 1433
  end

1434
  def test_resource_constraints
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
    get '/products/1'
    assert_equal 'pass', @response.headers['X-Cascade']
    get '/products'
    assert_equal 'products#root', @response.body
    get '/products/favorite'
    assert_equal 'products#favorite', @response.body
    get '/products/0001'
    assert_equal 'products#show', @response.body

    get '/products/1/images'
    assert_equal 'pass', @response.headers['X-Cascade']
    get '/products/0001/images'
    assert_equal 'images#index', @response.body
    get '/products/0001/images/0001'
    assert_equal 'images#show', @response.body

    get '/dashboard', {}, {'REMOTE_ADDR' => '10.0.0.100'}
    assert_equal 'pass', @response.headers['X-Cascade']
    get '/dashboard', {}, {'REMOTE_ADDR' => '192.168.1.100'}
    assert_equal 'dashboards#show', @response.body
1455 1456
  end

1457 1458 1459 1460 1461 1462
  def test_root_works_in_the_resources_scope
    get '/products'
    assert_equal 'products#root', @response.body
    assert_equal '/products', products_root_path
  end

1463
  def test_module_scope
1464 1465 1466
    get '/token'
    assert_equal 'api/tokens#show', @response.body
    assert_equal '/token', token_path
1467 1468
  end

1469
  def test_path_scope
1470 1471 1472
    get '/api/me'
    assert_equal 'mes#show', @response.body
    assert_equal '/api/me', me_path
1473

1474 1475
    get '/api'
    assert_equal 'mes#index', @response.body
1476 1477
  end

1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
  def test_symbol_scope
    get '/api/v2/me'
    assert_equal 'mes#show', @response.body
    assert_equal '/api/v2/me', v2_me_path

    get '/api/v2'
    assert_equal 'mes#index', @response.body

    get '/api/v3/admin/me'
    assert_equal 'mes#show', @response.body
  end

1490
  def test_url_generator_for_generic_route
1491 1492
    get 'whatever/foo/bar'
    assert_equal 'foo#bar', @response.body
1493

1494 1495
    assert_equal 'http://www.example.com/whatever/foo/bar/1',
      url_for(:controller => "foo", :action => "bar", :id => 1)
1496 1497
  end

1498
  def test_url_generator_for_namespaced_generic_route
1499 1500
    get 'whatever/foo/bar/show'
    assert_equal 'foo/bar#show', @response.body
1501

1502 1503
    get 'whatever/foo/bar/show/1'
    assert_equal 'foo/bar#show', @response.body
1504

1505 1506
    assert_equal 'http://www.example.com/whatever/foo/bar/show',
      url_for(:controller => "foo/bar", :action => "show")
1507

1508 1509
    assert_equal 'http://www.example.com/whatever/foo/bar/show/1',
      url_for(:controller => "foo/bar", :action => "show", :id => '1')
1510 1511
  end

1512
  def test_assert_recognizes_account_overview
1513
    assert_recognizes({:controller => "account", :action => "overview"}, "/account/overview")
1514 1515
  end

1516
  def test_resource_new_actions
1517 1518 1519 1520 1521
    assert_equal '/replies/new/preview', preview_new_reply_path
    assert_equal '/pt/projetos/novo/preview', preview_new_pt_project_path
    assert_equal '/pt/administrador/novo/preview', preview_new_pt_admin_path
    assert_equal '/pt/products/novo/preview', preview_new_pt_product_path
    assert_equal '/profile/new/preview', preview_new_profile_path
1522

1523 1524
    post '/replies/new/preview'
    assert_equal 'replies#preview', @response.body
1525

1526 1527
    post '/pt/projetos/novo/preview'
    assert_equal 'projects#preview', @response.body
1528

1529 1530
    post '/pt/administrador/novo/preview'
    assert_equal 'admins#preview', @response.body
1531

1532 1533
    post '/pt/products/novo/preview'
    assert_equal 'products#preview', @response.body
1534

1535 1536
    post '/profile/new/preview'
    assert_equal 'profiles#preview', @response.body
1537 1538
  end

1539
  def test_resource_merges_options_from_scope
1540
    assert_raise(NameError) { new_account_path }
1541

1542 1543
    get '/account/new'
    assert_equal 404, status
1544 1545 1546
  end

  def test_resources_merges_options_from_scope
1547
    assert_raise(NoMethodError) { edit_product_path('1') }
1548

1549 1550
    get '/products/1/edit'
    assert_equal 404, status
1551

1552
    assert_raise(NoMethodError) { edit_product_image_path('1', '2') }
1553

1554 1555
    post '/products/1/images/2/edit'
    assert_equal 404, status
1556 1557
  end

1558
  def test_shallow_nested_resources
1559 1560 1561
    get '/api/teams'
    assert_equal 'api/teams#index', @response.body
    assert_equal '/api/teams', api_teams_path
1562

1563 1564 1565
    get '/api/teams/new'
    assert_equal 'api/teams#new', @response.body
    assert_equal '/api/teams/new', new_api_team_path
1566

1567 1568 1569
    get '/api/teams/1'
    assert_equal 'api/teams#show', @response.body
    assert_equal '/api/teams/1', api_team_path(:id => '1')
1570

1571 1572 1573
    get '/api/teams/1/edit'
    assert_equal 'api/teams#edit', @response.body
    assert_equal '/api/teams/1/edit', edit_api_team_path(:id => '1')
1574

1575 1576 1577
    get '/api/teams/1/players'
    assert_equal 'api/players#index', @response.body
    assert_equal '/api/teams/1/players', api_team_players_path(:team_id => '1')
1578

1579 1580 1581
    get '/api/teams/1/players/new'
    assert_equal 'api/players#new', @response.body
    assert_equal '/api/teams/1/players/new', new_api_team_player_path(:team_id => '1')
1582

1583 1584 1585
    get '/api/players/2'
    assert_equal 'api/players#show', @response.body
    assert_equal '/api/players/2', api_player_path(:id => '2')
1586

1587 1588 1589
    get '/api/players/2/edit'
    assert_equal 'api/players#edit', @response.body
    assert_equal '/api/players/2/edit', edit_api_player_path(:id => '2')
1590

1591 1592 1593
    get '/api/teams/1/captain'
    assert_equal 'api/captains#show', @response.body
    assert_equal '/api/teams/1/captain', api_team_captain_path(:team_id => '1')
1594

1595 1596 1597
    get '/api/teams/1/captain/new'
    assert_equal 'api/captains#new', @response.body
    assert_equal '/api/teams/1/captain/new', new_api_team_captain_path(:team_id => '1')
1598

1599 1600 1601
    get '/api/teams/1/captain/edit'
    assert_equal 'api/captains#edit', @response.body
    assert_equal '/api/teams/1/captain/edit', edit_api_team_captain_path(:team_id => '1')
1602

1603 1604 1605
    get '/threads'
    assert_equal 'threads#index', @response.body
    assert_equal '/threads', threads_path
1606

1607 1608 1609
    get '/threads/new'
    assert_equal 'threads#new', @response.body
    assert_equal '/threads/new', new_thread_path
1610

1611 1612 1613
    get '/threads/1'
    assert_equal 'threads#show', @response.body
    assert_equal '/threads/1', thread_path(:id => '1')
1614

1615 1616 1617
    get '/threads/1/edit'
    assert_equal 'threads#edit', @response.body
    assert_equal '/threads/1/edit', edit_thread_path(:id => '1')
1618

1619 1620 1621
    get '/threads/1/owner'
    assert_equal 'owners#show', @response.body
    assert_equal '/threads/1/owner', thread_owner_path(:thread_id => '1')
1622

1623 1624 1625
    get '/threads/1/messages'
    assert_equal 'messages#index', @response.body
    assert_equal '/threads/1/messages', thread_messages_path(:thread_id => '1')
1626

1627 1628 1629
    get '/threads/1/messages/new'
    assert_equal 'messages#new', @response.body
    assert_equal '/threads/1/messages/new', new_thread_message_path(:thread_id => '1')
1630

1631 1632 1633
    get '/messages/2'
    assert_equal 'messages#show', @response.body
    assert_equal '/messages/2', message_path(:id => '2')
1634

1635 1636 1637
    get '/messages/2/edit'
    assert_equal 'messages#edit', @response.body
    assert_equal '/messages/2/edit', edit_message_path(:id => '2')
1638

1639 1640 1641
    get '/messages/2/comments'
    assert_equal 'comments#index', @response.body
    assert_equal '/messages/2/comments', message_comments_path(:message_id => '2')
1642

1643 1644 1645
    get '/messages/2/comments/new'
    assert_equal 'comments#new', @response.body
    assert_equal '/messages/2/comments/new', new_message_comment_path(:message_id => '2')
1646

1647 1648 1649
    get '/comments/3'
    assert_equal 'comments#show', @response.body
    assert_equal '/comments/3', comment_path(:id => '3')
1650

1651 1652 1653
    get '/comments/3/edit'
    assert_equal 'comments#edit', @response.body
    assert_equal '/comments/3/edit', edit_comment_path(:id => '3')
1654

1655 1656 1657
    post '/comments/3/preview'
    assert_equal 'comments#preview', @response.body
    assert_equal '/comments/3/preview', preview_comment_path(:id => '3')
1658 1659
  end

1660
  def test_shallow_nested_resources_within_scope
1661 1662 1663
    get '/hello/notes/1/trackbacks'
    assert_equal 'trackbacks#index', @response.body
    assert_equal '/hello/notes/1/trackbacks', note_trackbacks_path(:note_id => 1)
1664

1665 1666 1667
    get '/hello/notes/1/edit'
    assert_equal 'notes#edit', @response.body
    assert_equal '/hello/notes/1/edit', edit_note_path(:id => '1')
1668

1669 1670 1671
    get '/hello/notes/1/trackbacks/new'
    assert_equal 'trackbacks#new', @response.body
    assert_equal '/hello/notes/1/trackbacks/new', new_note_trackback_path(:note_id => 1)
1672

1673 1674 1675
    get '/hello/trackbacks/1'
    assert_equal 'trackbacks#show', @response.body
    assert_equal '/hello/trackbacks/1', trackback_path(:id => '1')
1676

1677 1678 1679
    get '/hello/trackbacks/1/edit'
    assert_equal 'trackbacks#edit', @response.body
    assert_equal '/hello/trackbacks/1/edit', edit_trackback_path(:id => '1')
1680

1681 1682
    put '/hello/trackbacks/1'
    assert_equal 'trackbacks#update', @response.body
1683

1684 1685
    post '/hello/notes/1/trackbacks'
    assert_equal 'trackbacks#create', @response.body
1686

1687 1688
    delete '/hello/trackbacks/1'
    assert_equal 'trackbacks#destroy', @response.body
1689

1690 1691
    get '/hello/notes'
    assert_equal 'notes#index', @response.body
1692

1693 1694
    post '/hello/notes'
    assert_equal 'notes#create', @response.body
1695

1696 1697 1698
    get '/hello/notes/new'
    assert_equal 'notes#new', @response.body
    assert_equal '/hello/notes/new', new_note_path
1699

1700 1701 1702
    get '/hello/notes/1'
    assert_equal 'notes#show', @response.body
    assert_equal '/hello/notes/1', note_path(:id => 1)
1703

1704 1705
    put '/hello/notes/1'
    assert_equal 'notes#update', @response.body
1706

1707 1708
    delete '/hello/notes/1'
    assert_equal 'notes#destroy', @response.body
1709 1710
  end

1711
  def test_custom_resource_routes_are_scoped
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730
    assert_equal '/customers/recent', recent_customers_path
    assert_equal '/customers/1/profile', profile_customer_path(:id => '1')
    assert_equal '/customers/1/secret/profile', secret_profile_customer_path(:id => '1')
    assert_equal '/customers/new/preview', another_preview_new_customer_path
    assert_equal '/customers/1/avatar/thumbnail.jpg', thumbnail_customer_avatar_path(:customer_id => '1', :format => :jpg)
    assert_equal '/customers/1/invoices/outstanding', outstanding_customer_invoices_path(:customer_id => '1')
    assert_equal '/customers/1/invoices/2/print', print_customer_invoice_path(:customer_id => '1', :id => '2')
    assert_equal '/customers/1/invoices/new/preview', preview_new_customer_invoice_path(:customer_id => '1')
    assert_equal '/customers/1/notes/new/preview', preview_new_customer_note_path(:customer_id => '1')
    assert_equal '/notes/1/print', print_note_path(:id => '1')
    assert_equal '/api/customers/recent', recent_api_customers_path
    assert_equal '/api/customers/1/profile', profile_api_customer_path(:id => '1')
    assert_equal '/api/customers/new/preview', preview_new_api_customer_path

    get '/customers/1/invoices/overdue'
    assert_equal 'invoices#overdue', @response.body

    get '/customers/1/secret/profile'
    assert_equal 'customers#secret', @response.body
1731 1732
  end

1733
  def test_shallow_nested_routes_ignore_module
1734 1735 1736 1737 1738 1739 1740
    get '/errors/1/notices'
    assert_equal 'api/notices#index', @response.body
    assert_equal '/errors/1/notices', error_notices_path(:error_id => '1')

    get '/notices/1'
    assert_equal 'api/notices#show', @response.body
    assert_equal '/notices/1', notice_path(:id => '1')
1741 1742
  end

1743
  def test_non_greedy_regexp
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
    get '/api/1.0/users'
    assert_equal 'api/users#index', @response.body
    assert_equal '/api/1.0/users', api_users_path(:version => '1.0')

    get '/api/1.0/users.json'
    assert_equal 'api/users#index', @response.body
    assert_equal true, @request.format.json?
    assert_equal '/api/1.0/users.json', api_users_path(:version => '1.0', :format => :json)

    get '/api/1.0/users/first.last'
    assert_equal 'api/users#show', @response.body
    assert_equal 'first.last', @request.params[:id]
    assert_equal '/api/1.0/users/first.last', api_user_path(:version => '1.0', :id => 'first.last')

    get '/api/1.0/users/first.last.xml'
    assert_equal 'api/users#show', @response.body
    assert_equal 'first.last', @request.params[:id]
    assert_equal true, @request.format.xml?
    assert_equal '/api/1.0/users/first.last.xml', api_user_path(:version => '1.0', :id => 'first.last', :format => :xml)
1763 1764
  end

1765
  def test_glob_parameter_accepts_regexp
1766 1767
    get '/en/path/to/existing/file.html'
    assert_equal 200, @response.status
1768 1769
  end

1770
  def test_resources_controller_name_is_not_pluralized
1771 1772
    get '/content'
    assert_equal 'content#index', @response.body
1773 1774
  end

1775
  def test_url_generator_for_optional_prefix_dynamic_segment
1776 1777 1778 1779 1780 1781 1782 1783 1784
    get '/bob/followers'
    assert_equal 'followers#index', @response.body
    assert_equal 'http://www.example.com/bob/followers',
      url_for(:controller => "followers", :action => "index", :username => "bob")

    get '/followers'
    assert_equal 'followers#index', @response.body
    assert_equal 'http://www.example.com/followers',
      url_for(:controller => "followers", :action => "index", :username => nil)
1785 1786 1787
  end

  def test_url_generator_for_optional_suffix_static_and_dynamic_segment
1788 1789 1790 1791 1792 1793 1794 1795 1796
    get '/groups/user/bob'
    assert_equal 'groups#index', @response.body
    assert_equal 'http://www.example.com/groups/user/bob',
      url_for(:controller => "groups", :action => "index", :username => "bob")

    get '/groups'
    assert_equal 'groups#index', @response.body
    assert_equal 'http://www.example.com/groups',
      url_for(:controller => "groups", :action => "index", :username => nil)
1797 1798 1799
  end

  def test_url_generator_for_optional_prefix_static_and_dynamic_segment
1800 1801 1802 1803 1804 1805 1806 1807 1808
    get 'user/bob/photos'
    assert_equal 'photos#index', @response.body
    assert_equal 'http://www.example.com/user/bob/photos',
      url_for(:controller => "photos", :action => "index", :username => "bob")

    get 'photos'
    assert_equal 'photos#index', @response.body
    assert_equal 'http://www.example.com/photos',
      url_for(:controller => "photos", :action => "index", :username => nil)
1809 1810
  end

1811
  def test_url_recognition_for_optional_static_segments
1812 1813
    get '/groups/discussions/messages'
    assert_equal 'messages#index', @response.body
1814

1815 1816
    get '/groups/discussions/messages/1'
    assert_equal 'messages#show', @response.body
1817

1818 1819
    get '/groups/messages'
    assert_equal 'messages#index', @response.body
1820

1821 1822
    get '/groups/messages/1'
    assert_equal 'messages#show', @response.body
1823

1824 1825
    get '/discussions/messages'
    assert_equal 'messages#index', @response.body
1826

1827 1828
    get '/discussions/messages/1'
    assert_equal 'messages#show', @response.body
1829

1830 1831
    get '/messages'
    assert_equal 'messages#index', @response.body
1832

1833 1834
    get '/messages/1'
    assert_equal 'messages#show', @response.body
1835 1836
  end

1837
  def test_router_removes_invalid_conditions
1838 1839 1840
    get '/tickets'
    assert_equal 'tickets#index', @response.body
    assert_equal '/tickets', tickets_path
1841 1842
  end

1843
  def test_constraints_are_merged_from_scope
1844 1845 1846 1847 1848 1849
    get '/movies/0001'
    assert_equal 'movies#show', @response.body
    assert_equal '/movies/0001', movie_path(:id => '0001')

    get '/movies/00001'
    assert_equal 'Not Found', @response.body
1850
    assert_raises(ActionController::UrlGenerationError){ movie_path(:id => '00001') }
1851 1852 1853 1854 1855 1856 1857

    get '/movies/0001/reviews'
    assert_equal 'reviews#index', @response.body
    assert_equal '/movies/0001/reviews', movie_reviews_path(:movie_id => '0001')

    get '/movies/00001/reviews'
    assert_equal 'Not Found', @response.body
1858
    assert_raises(ActionController::UrlGenerationError){ movie_reviews_path(:movie_id => '00001') }
1859 1860 1861 1862 1863 1864 1865

    get '/movies/0001/reviews/0001'
    assert_equal 'reviews#show', @response.body
    assert_equal '/movies/0001/reviews/0001', movie_review_path(:movie_id => '0001', :id => '0001')

    get '/movies/00001/reviews/0001'
    assert_equal 'Not Found', @response.body
1866
    assert_raises(ActionController::UrlGenerationError){ movie_path(:movie_id => '00001', :id => '00001') }
1867 1868 1869 1870 1871 1872 1873

    get '/movies/0001/trailer'
    assert_equal 'trailers#show', @response.body
    assert_equal '/movies/0001/trailer', movie_trailer_path(:movie_id => '0001')

    get '/movies/00001/trailer'
    assert_equal 'Not Found', @response.body
1874
    assert_raises(ActionController::UrlGenerationError){ movie_trailer_path(:movie_id => '00001') }
1875
  end
1876

1877
  def test_only_should_be_read_from_scope
1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
    get '/only/clubs'
    assert_equal 'only/clubs#index', @response.body
    assert_equal '/only/clubs', only_clubs_path

    get '/only/clubs/1/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_only_club_path(:id => '1') }

    get '/only/clubs/1/players'
    assert_equal 'only/players#index', @response.body
    assert_equal '/only/clubs/1/players', only_club_players_path(:club_id => '1')

    get '/only/clubs/1/players/2/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_only_club_player_path(:club_id => '1', :id => '2') }

    get '/only/clubs/1/chairman'
    assert_equal 'only/chairmen#show', @response.body
    assert_equal '/only/clubs/1/chairman', only_club_chairman_path(:club_id => '1')

    get '/only/clubs/1/chairman/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_only_club_chairman_path(:club_id => '1') }
1901
  end
1902

1903
  def test_except_should_be_read_from_scope
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926
    get '/except/clubs'
    assert_equal 'except/clubs#index', @response.body
    assert_equal '/except/clubs', except_clubs_path

    get '/except/clubs/1/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_except_club_path(:id => '1') }

    get '/except/clubs/1/players'
    assert_equal 'except/players#index', @response.body
    assert_equal '/except/clubs/1/players', except_club_players_path(:club_id => '1')

    get '/except/clubs/1/players/2/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_except_club_player_path(:club_id => '1', :id => '2') }

    get '/except/clubs/1/chairman'
    assert_equal 'except/chairmen#show', @response.body
    assert_equal '/except/clubs/1/chairman', except_club_chairman_path(:club_id => '1')

    get '/except/clubs/1/chairman/edit'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { edit_except_club_chairman_path(:club_id => '1') }
1927
  end
1928

1929
  def test_only_option_should_override_scope
1930 1931 1932 1933 1934 1935 1936
    get '/only/sectors'
    assert_equal 'only/sectors#index', @response.body
    assert_equal '/only/sectors', only_sectors_path

    get '/only/sectors/1'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { only_sector_path(:id => '1') }
1937 1938 1939
  end

  def test_only_option_should_not_inherit
1940 1941 1942 1943 1944 1945 1946
    get '/only/sectors/1/companies/2'
    assert_equal 'only/companies#show', @response.body
    assert_equal '/only/sectors/1/companies/2', only_sector_company_path(:sector_id => '1', :id => '2')

    get '/only/sectors/1/leader'
    assert_equal 'only/leaders#show', @response.body
    assert_equal '/only/sectors/1/leader', only_sector_leader_path(:sector_id => '1')
1947
  end
1948

1949
  def test_except_option_should_override_scope
1950 1951 1952 1953 1954 1955 1956
    get '/except/sectors'
    assert_equal 'except/sectors#index', @response.body
    assert_equal '/except/sectors', except_sectors_path

    get '/except/sectors/1'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { except_sector_path(:id => '1') }
1957 1958 1959
  end

  def test_except_option_should_not_inherit
1960 1961 1962 1963 1964 1965 1966
    get '/except/sectors/1/companies/2'
    assert_equal 'except/companies#show', @response.body
    assert_equal '/except/sectors/1/companies/2', except_sector_company_path(:sector_id => '1', :id => '2')

    get '/except/sectors/1/leader'
    assert_equal 'except/leaders#show', @response.body
    assert_equal '/except/sectors/1/leader', except_sector_leader_path(:sector_id => '1')
1967 1968 1969
  end

  def test_except_option_should_override_scoped_only
1970 1971 1972 1973 1974 1975 1976
    get '/only/sectors/1/managers'
    assert_equal 'only/managers#index', @response.body
    assert_equal '/only/sectors/1/managers', only_sector_managers_path(:sector_id => '1')

    get '/only/sectors/1/managers/2'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { only_sector_manager_path(:sector_id => '1', :id => '2') }
1977 1978 1979
  end

  def test_only_option_should_override_scoped_except
1980 1981 1982 1983 1984 1985 1986
    get '/except/sectors/1/managers'
    assert_equal 'except/managers#index', @response.body
    assert_equal '/except/sectors/1/managers', except_sector_managers_path(:sector_id => '1')

    get '/except/sectors/1/managers/2'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { except_sector_manager_path(:sector_id => '1', :id => '2') }
1987 1988 1989
  end

  def test_only_scope_should_override_parent_scope
1990 1991 1992 1993 1994 1995 1996
    get '/only/sectors/1/companies/2/divisions'
    assert_equal 'only/divisions#index', @response.body
    assert_equal '/only/sectors/1/companies/2/divisions', only_sector_company_divisions_path(:sector_id => '1', :company_id => '2')

    get '/only/sectors/1/companies/2/divisions/3'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { only_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') }
1997 1998 1999
  end

  def test_except_scope_should_override_parent_scope
2000 2001 2002 2003 2004 2005 2006
    get '/except/sectors/1/companies/2/divisions'
    assert_equal 'except/divisions#index', @response.body
    assert_equal '/except/sectors/1/companies/2/divisions', except_sector_company_divisions_path(:sector_id => '1', :company_id => '2')

    get '/except/sectors/1/companies/2/divisions/3'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { except_sector_company_division_path(:sector_id => '1', :company_id => '2', :id => '3') }
2007
  end
2008

2009
  def test_except_scope_should_override_parent_only_scope
2010 2011 2012 2013 2014 2015 2016
    get '/only/sectors/1/companies/2/departments'
    assert_equal 'only/departments#index', @response.body
    assert_equal '/only/sectors/1/companies/2/departments', only_sector_company_departments_path(:sector_id => '1', :company_id => '2')

    get '/only/sectors/1/companies/2/departments/3'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { only_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') }
2017
  end
2018

2019
  def test_only_scope_should_override_parent_except_scope
2020 2021 2022 2023 2024 2025 2026
    get '/except/sectors/1/companies/2/departments'
    assert_equal 'except/departments#index', @response.body
    assert_equal '/except/sectors/1/companies/2/departments', except_sector_company_departments_path(:sector_id => '1', :company_id => '2')

    get '/except/sectors/1/companies/2/departments/3'
    assert_equal 'Not Found', @response.body
    assert_raise(NoMethodError) { except_sector_company_department_path(:sector_id => '1', :company_id => '2', :id => '3') }
2027 2028
  end

2029
  def test_resources_are_not_pluralized
2030 2031 2032
    get '/transport/taxis'
    assert_equal 'transport/taxis#index', @response.body
    assert_equal '/transport/taxis', transport_taxis_path
2033

2034 2035 2036
    get '/transport/taxis/new'
    assert_equal 'transport/taxis#new', @response.body
    assert_equal '/transport/taxis/new', new_transport_taxi_path
2037

2038 2039
    post '/transport/taxis'
    assert_equal 'transport/taxis#create', @response.body
2040

2041 2042 2043
    get '/transport/taxis/1'
    assert_equal 'transport/taxis#show', @response.body
    assert_equal '/transport/taxis/1', transport_taxi_path(:id => '1')
2044

2045 2046 2047
    get '/transport/taxis/1/edit'
    assert_equal 'transport/taxis#edit', @response.body
    assert_equal '/transport/taxis/1/edit', edit_transport_taxi_path(:id => '1')
2048

2049 2050
    put '/transport/taxis/1'
    assert_equal 'transport/taxis#update', @response.body
2051

2052 2053
    delete '/transport/taxis/1'
    assert_equal 'transport/taxis#destroy', @response.body
2054 2055 2056
  end

  def test_singleton_resources_are_not_singularized
2057 2058 2059
    get '/medical/taxis/new'
    assert_equal 'medical/taxis#new', @response.body
    assert_equal '/medical/taxis/new', new_medical_taxis_path
2060

2061 2062
    post '/medical/taxis'
    assert_equal 'medical/taxis#create', @response.body
2063

2064 2065 2066
    get '/medical/taxis'
    assert_equal 'medical/taxis#show', @response.body
    assert_equal '/medical/taxis', medical_taxis_path
2067

2068 2069 2070
    get '/medical/taxis/edit'
    assert_equal 'medical/taxis#edit', @response.body
    assert_equal '/medical/taxis/edit', edit_medical_taxis_path
2071

2072 2073
    put '/medical/taxis'
    assert_equal 'medical/taxis#update', @response.body
2074

2075 2076
    delete '/medical/taxis'
    assert_equal 'medical/taxis#destroy', @response.body
2077 2078
  end

2079
  def test_greedy_resource_id_regexp_doesnt_match_edit_and_custom_action
2080 2081 2082 2083 2084 2085 2086
    get '/sections/1/edit'
    assert_equal 'sections#edit', @response.body
    assert_equal '/sections/1/edit', edit_section_path(:id => '1')

    get '/sections/1/preview'
    assert_equal 'sections#preview', @response.body
    assert_equal '/sections/1/preview', preview_section_path(:id => '1')
2087 2088
  end

2089
  def test_resource_constraints_are_pushed_to_scope
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
    get '/wiki/articles/Ruby_on_Rails_3.0'
    assert_equal 'wiki/articles#show', @response.body
    assert_equal '/wiki/articles/Ruby_on_Rails_3.0', wiki_article_path(:id => 'Ruby_on_Rails_3.0')

    get '/wiki/articles/Ruby_on_Rails_3.0/comments/new'
    assert_equal 'wiki/comments#new', @response.body
    assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments/new', new_wiki_article_comment_path(:article_id => 'Ruby_on_Rails_3.0')

    post '/wiki/articles/Ruby_on_Rails_3.0/comments'
    assert_equal 'wiki/comments#create', @response.body
    assert_equal '/wiki/articles/Ruby_on_Rails_3.0/comments', wiki_article_comments_path(:article_id => 'Ruby_on_Rails_3.0')
2101 2102
  end

2103
  def test_resources_path_can_be_a_symbol
2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114
    get '/pages'
    assert_equal 'wiki_pages#index', @response.body
    assert_equal '/pages', wiki_pages_path

    get '/pages/Ruby_on_Rails'
    assert_equal 'wiki_pages#show', @response.body
    assert_equal '/pages/Ruby_on_Rails', wiki_page_path(:id => 'Ruby_on_Rails')

    get '/my_account'
    assert_equal 'wiki_accounts#show', @response.body
    assert_equal '/my_account', wiki_account_path
2115 2116
  end

2117
  def test_redirect_https
2118 2119 2120
    with_https do
      get '/secure'
      verify_redirect 'https://www.example.com/secure/login'
2121 2122 2123
    end
  end

2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137
  def test_symbolized_path_parameters_is_not_stale
    get '/countries/France'
    assert_equal 'countries#index', @response.body

    get '/countries/France/cities'
    assert_equal 'countries#cities', @response.body

    get '/countries/UK'
    verify_redirect 'http://www.example.com/countries/all'

    get '/countries/UK/cities'
    verify_redirect 'http://www.example.com/countries/all/cities'
  end

2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151
  def test_constraints_block_not_carried_to_following_routes
    get '/italians/writers'
    assert_equal 'Not Found', @response.body

    get '/italians/sculptors'
    assert_equal 'italians#sculptors', @response.body

    get '/italians/painters/botticelli'
    assert_equal 'Not Found', @response.body

    get '/italians/painters/michelangelo'
    assert_equal 'italians#painters', @response.body
  end

2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169
  def test_custom_resource_actions_defined_using_string
    get '/customers/inactive'
    assert_equal 'customers#inactive', @response.body
    assert_equal '/customers/inactive', inactive_customers_path

    post '/customers/1/deactivate'
    assert_equal 'customers#deactivate', @response.body
    assert_equal '/customers/1/deactivate', deactivate_customer_path(:id => '1')

    get '/customers/old'
    assert_equal 'customers#old', @response.body
    assert_equal '/customers/old', stale_customers_path

    get '/customers/1/invoices/aged/3'
    assert_equal 'invoices#aged', @response.body
    assert_equal '/customers/1/invoices/aged/3', aged_customer_invoices_path(:customer_id => '1', :months => '3')
  end

2170 2171 2172 2173 2174 2175
  def test_route_defined_in_resources_scope_level
    get '/customers/1/export'
    assert_equal 'customers#export', @response.body
    assert_equal '/customers/1/export', customer_export_path(:customer_id => '1')
  end

2176 2177 2178 2179 2180 2181
  def test_named_character_classes_in_regexp_constraints
    get '/purchases/315004be7e/Ruby_on_Rails_3.pdf'
    assert_equal 'purchases#fetch', @response.body
    assert_equal '/purchases/315004be7e/Ruby_on_Rails_3.pdf', purchase_path(:token => '315004be7e', :filename => 'Ruby_on_Rails_3.pdf')
  end

2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
  def test_nested_resource_constraints
    get '/lists/01234012340123401234fffff'
    assert_equal 'lists#show', @response.body
    assert_equal '/lists/01234012340123401234fffff', list_path(:id => '01234012340123401234fffff')

    get '/lists/01234012340123401234fffff/todos/1'
    assert_equal 'todos#show', @response.body
    assert_equal '/lists/01234012340123401234fffff/todos/1', list_todo_path(:list_id => '01234012340123401234fffff', :id => '1')

    get '/lists/2/todos/1'
    assert_equal 'Not Found', @response.body
2193
    assert_raises(ActionController::UrlGenerationError){ list_todo_path(:list_id => '2', :id => '1') }
2194 2195
  end

2196 2197
  def test_named_routes_collision_is_avoided_unless_explicitly_given_as
    assert_equal "/c/1", routes_collision_path(1)
A
Aaron Patterson 已提交
2198
    assert_equal "/fc/1", routes_forced_collision_path(1)
2199 2200
  end

2201 2202 2203 2204 2205
  def test_redirect_argument_error
    routes = Class.new { include ActionDispatch::Routing::Redirection }.new
    assert_raises(ArgumentError) { routes.redirect Object.new }
  end

2206 2207 2208 2209
  def test_explicitly_avoiding_the_named_route
    assert !respond_to?(:routes_no_collision_path)
  end

2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239
  def test_controller_name_with_leading_slash_raise_error
    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/feeds/:service', :to => '/feeds#show' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/feeds/:service', :controller => '/feeds', :action => 'show' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/api/feeds/:service', :to => '/api/feeds#show' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { controller("/feeds") { get '/feeds/:service', :to => :show } }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { resources :feeds, :controller => '/feeds' }
      end
    end
2240 2241
  end

2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273
  def test_invalid_route_name_raises_error
    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/products', :to => 'products#index', :as => 'products ' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/products', :to => 'products#index', :as => ' products' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/products', :to => 'products#index', :as => 'products!' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/products', :to => 'products#index', :as => 'products index' }
      end
    end

    assert_raise(ArgumentError) do
      self.class.stub_controllers do |routes|
        routes.draw { get '/products', :to => 'products#index', :as => '1products' }
      end
    end
  end

2274 2275 2276 2277 2278 2279
  def test_nested_route_in_nested_resource
    get "/posts/1/comments/2/views"
    assert_equal "comments#views", @response.body
    assert_equal "/posts/1/comments/2/views", post_comment_views_path(:post_id => '1', :comment_id => '2')
  end

2280 2281 2282 2283 2284 2285
  def test_root_in_deeply_nested_scope
    get "/posts/1/admin"
    assert_equal "admin/index#index", @response.body
    assert_equal "/posts/1/admin", post_admin_root_path(:post_id => '1')
  end

2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298
  def test_custom_param
    get '/profiles/bob'
    assert_equal 'profiles#show', @response.body
    assert_equal 'bob', @request.params[:username]

    get '/profiles/bob/details'
    assert_equal 'bob', @request.params[:username]

    get '/profiles/bob/messages/34'
    assert_equal 'bob', @request.params[:profile_username]
    assert_equal '34', @request.params[:id]
  end

2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309
  def test_custom_param_constraint
    get '/profiles/bob1'
    assert_equal 404, @response.status

    get '/profiles/bob1/details'
    assert_equal 404, @response.status

    get '/profiles/bob1/messages/34'
    assert_equal 404, @response.status
  end

2310 2311 2312 2313 2314 2315
  def test_shallow_custom_param
    get '/downloads/0c0c0b68-d24b-11e1-a861-001ff3fffe6f.zip'
    assert_equal 'downloads#show', @response.body
    assert_equal '0c0c0b68-d24b-11e1-a861-001ff3fffe6f', @request.params[:download]
  end

2316
private
2317 2318 2319 2320 2321 2322 2323 2324
  def with_https
    old_https = https?
    https!
    yield
  ensure
    https!(old_https)
  end

2325 2326 2327 2328 2329 2330 2331 2332 2333
  def verify_redirect(url, status=301)
    assert_equal status, @response.status
    assert_equal url, @response.headers['Location']
    assert_equal expected_redirect_body(url), @response.body
  end

  def expected_redirect_body(url)
    %(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>)
  end
2334
end
2335

2336
class TestAppendingRoutes < ActionDispatch::IntegrationTest
C
Carl Lerche 已提交
2337 2338 2339 2340
  def simple_app(resp)
    lambda { |e| [ 200, { 'Content-Type' => 'text/plain' }, [resp] ] }
  end

A
Aaron Patterson 已提交
2341 2342
  def setup
    super
C
Carl Lerche 已提交
2343 2344 2345
    s = self
    @app = ActionDispatch::Routing::RouteSet.new
    @app.append do
2346 2347
      get '/hello'   => s.simple_app('fail')
      get '/goodbye' => s.simple_app('goodbye')
C
Carl Lerche 已提交
2348 2349 2350
    end

    @app.draw do
2351
      get '/hello' => s.simple_app('hello')
C
Carl Lerche 已提交
2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369
    end
  end

  def test_goodbye_should_be_available
    get '/goodbye'
    assert_equal 'goodbye', @response.body
  end

  def test_hello_should_not_be_overwritten
    get '/hello'
    assert_equal 'hello', @response.body
  end

  def test_missing_routes_are_still_missing
    get '/random'
    assert_equal 404, @response.status
  end
end
2370

2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396
class TestNamespaceWithControllerOption < ActionDispatch::IntegrationTest
  module ::Admin
    class StorageFilesController < ActionController::Base
      def index
        render :text => "admin/storage_files#index"
      end
    end
  end

  DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new
  DefaultScopeRoutes.draw do
    namespace :admin do
      resources :storage_files, :controller => "StorageFiles"
    end
  end

  def app
    DefaultScopeRoutes
  end

  def test_controller_options
    get '/admin/storage_files'
    assert_equal "admin/storage_files#index", @response.body
  end
end

2397
class TestDefaultScope < ActionDispatch::IntegrationTest
2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423
  module ::Blog
    class PostsController < ActionController::Base
      def index
        render :text => "blog/posts#index"
      end
    end
  end

  DefaultScopeRoutes = ActionDispatch::Routing::RouteSet.new
  DefaultScopeRoutes.default_scope = {:module => :blog}
  DefaultScopeRoutes.draw do
    resources :posts
  end

  def app
    DefaultScopeRoutes
  end

  include DefaultScopeRoutes.url_helpers

  def test_default_scope
    get '/posts'
    assert_equal "blog/posts#index", @response.body
  end
end

2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
class TestHttpMethods < ActionDispatch::IntegrationTest
  RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
  RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
  RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
  RFC3648 = %w(ORDERPATCH)
  RFC3744 = %w(ACL)
  RFC5323 = %w(SEARCH)
  RFC5789 = %w(PATCH)

  def simple_app(response)
    lambda { |env| [ 200, { 'Content-Type' => 'text/plain' }, [response] ] }
  end

  setup do
    s = self
    @app = ActionDispatch::Routing::RouteSet.new

    @app.draw do
      (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
        match '/' => s.simple_app(method), :via => method.underscore.to_sym
      end
    end
  end

  (RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC5789).each do |method|
    test "request method #{method.underscore} can be matched" do
      get '/', nil, 'REQUEST_METHOD' => method
      assert_equal method, @response.body
    end
  end
end
2455 2456 2457 2458

class TestUriPathEscaping < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
2459
      get '/:segment' => lambda { |env|
2460 2461 2462
        path_params = env['action_dispatch.request.path_parameters']
        [200, { 'Content-Type' => 'text/plain' }, [path_params[:segment]]]
      }, :as => :segment
2463

2464
      get '/*splat' => lambda { |env|
2465 2466 2467
        path_params = env['action_dispatch.request.path_parameters']
        [200, { 'Content-Type' => 'text/plain' }, [path_params[:splat]]]
      }, :as => :splat
2468 2469 2470 2471 2472 2473
    end
  end

  include Routes.url_helpers
  def app; Routes end

2474 2475 2476 2477 2478 2479 2480
  test 'escapes generated path segment' do
    assert_equal '/a%20b/c+d', segment_path(:segment => 'a b/c+d')
  end

  test 'unescapes recognized path segment' do
    get '/a%20b%2Fc+d'
    assert_equal 'a b/c+d', @response.body
2481 2482
  end

2483 2484
  test 'escapes generated path splat' do
    assert_equal '/a%20b/c+d', splat_path(:splat => 'a b/c+d')
2485 2486
  end

2487 2488 2489
  test 'unescapes recognized path splat' do
    get '/a%20b/c+d'
    assert_equal 'a b/c+d', @response.body
2490 2491
  end
end
2492 2493 2494 2495

class TestUnicodePaths < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
2496
      get "/ほげ" => lambda { |env|
2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509
        [200, { 'Content-Type' => 'text/plain' }, []]
      }, :as => :unicode_path
    end
  end

  include Routes.url_helpers
  def app; Routes end

  test 'recognizes unicode path' do
    get "/#{Rack::Utils.escape("ほげ")}"
    assert_equal "200", @response.code
  end
end
2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525

class TestMultipleNestedController < ActionDispatch::IntegrationTest
  module ::Foo
    module Bar
      class BazController < ActionController::Base
        def index
          render :inline => "<%= url_for :controller => '/pooh', :action => 'index' %>"
        end
      end
    end
  end

  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      namespace :foo do
        namespace :bar do
2526
          get "baz" => "baz#index"
2527 2528
        end
      end
2529
      get "pooh" => "pooh#index"
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541
    end
  end

  include Routes.url_helpers
  def app; Routes end

  test "controller option which starts with '/' from multiple nested controller" do
    get "/foo/bar/baz"
    assert_equal "/pooh", @response.body
  end
end

K
kennyj 已提交
2542 2543 2544
class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
K
kennyj 已提交
2545 2546
      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }

2547 2548
      get "/~user" => ok
      get "/young-and-fine" => ok
K
kennyj 已提交
2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
    end
  end

  include Routes.url_helpers
  def app; Routes end

  test 'recognizes tilde path' do
    get "/~user"
    assert_equal "200", @response.code
  end

  test 'recognizes minus path' do
    get "/young-and-fine"
    assert_equal "200", @response.code
  end

end
2566 2567 2568 2569 2570 2571 2572

class TestRedirectInterpolation < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }

      get "/foo/:id" => redirect("/foo/bar/%{id}")
2573
      get "/bar/:id" => redirect(:path => "/foo/bar/%{id}")
2574 2575 2576 2577 2578 2579
      get "/foo/bar/:id" => ok
    end
  end

  def app; Routes end

2580
  test "redirect escapes interpolated parameters with redirect proc" do
2581 2582 2583 2584
    get "/foo/1%3E"
    verify_redirect "http://www.example.com/foo/bar/1%3E"
  end

2585 2586 2587 2588 2589
  test "redirect escapes interpolated parameters with option proc" do
    get "/bar/1%3E"
    verify_redirect "http://www.example.com/foo/bar/1%3E"
  end

2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600
private
  def verify_redirect(url, status=301)
    assert_equal status, @response.status
    assert_equal url, @response.headers['Location']
    assert_equal expected_redirect_body(url), @response.body
  end

  def expected_redirect_body(url)
    %(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>)
  end
end
2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619

class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }

      get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == 'foo' }
      get "/:bar" => ok
    end
  end

  def app; Routes end

  test "parameters are reset between constraint checks" do
    get "/bar"
    assert_equal nil, @request.params[:foo]
    assert_equal "bar", @request.params[:bar]
  end
end
2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643

class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
      get '/foo' => ok, as: :foo
    end
  end

  include Routes.url_helpers
  def app; Routes end

  test 'enabled when not mounted and default_url_options is empty' do
    assert Routes.url_helpers.optimize_routes_generation?
  end

  test 'named route called as singleton method' do
    assert_equal '/foo', Routes.url_helpers.foo_path
  end

  test 'named route called on included module' do
    assert_equal '/foo', foo_path
  end
end
2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675

class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest
  class CategoriesController < ActionController::Base
    def show
      render :text => "categories#show"
    end
  end

  class ProductsController < ActionController::Base
    def show
      render :text => "products#show"
    end
  end

  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      scope :module => "test_named_route_url_helpers" do
        get "/categories/:id" => 'categories#show', :as => :category
        get "/products/:id" => 'products#show', :as => :product
      end
    end
  end

  def app; Routes end

  include Routes.url_helpers

  test "url helpers do not ignore nil parameters when using non-optimized routes" do
    Routes.stubs(:optimize_routes_generation?).returns(false)

    get "/categories/1"
    assert_response :success
2676
    assert_raises(ActionController::UrlGenerationError) { product_path(nil) }
2677 2678
  end
end
2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720

class TestUrlConstraints < ActionDispatch::IntegrationTest
  Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
    app.draw do
      ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }

      constraints :subdomain => 'admin' do
        get '/' => ok, :as => :admin_root
      end

      scope :constraints => { :protocol => 'https://' } do
        get '/' => ok, :as => :secure_root
      end

      get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 }
    end
  end

  include Routes.url_helpers
  def app; Routes end

  test "constraints are copied to defaults when using constraints method" do
    assert_equal 'http://admin.example.com/', admin_root_url

    get 'http://admin.example.com/'
    assert_response :success
  end

  test "constraints are copied to defaults when using scope constraints hash" do
    assert_equal 'https://www.example.com/', secure_root_url

    get 'https://www.example.com/'
    assert_response :success
  end

  test "constraints are copied to defaults when using route constraints hash" do
    assert_equal 'http://www.example.com:8080/', alternate_root_url

    get 'http://www.example.com:8080/'
    assert_response :success
  end
end
2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750

class TestInvalidUrls < ActionDispatch::IntegrationTest
  class FooController < ActionController::Base
    def show
      render :text => "foo#show"
    end
  end

  test "invalid UTF-8 encoding returns a 400 Bad Request" do
    with_routing do |set|
      set.draw do
        get "/bar/:id", :to => redirect("/foo/show/%{id}")
        get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
        get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo"
        get "/:controller(/:action(/:id))"
      end

      get "/%E2%EF%BF%BD%A6"
      assert_response :bad_request

      get "/foo/%E2%EF%BF%BD%A6"
      assert_response :bad_request

      get "/foo/show/%E2%EF%BF%BD%A6"
      assert_response :bad_request

      get "/bar/%E2%EF%BF%BD%A6"
      assert_response :bad_request
    end
  end
2751
end
2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778

class TestOptionalRootSegments < ActionDispatch::IntegrationTest
  stub_controllers do |routes|
    Routes = routes
    Routes.draw do
      get '/(page/:page)', :to => 'pages#index', :as => :root
    end
  end

  def app
    Routes
  end

  include Routes.url_helpers

  def test_optional_root_segments
    get '/'
    assert_equal 'pages#index', @response.body
    assert_equal '/', root_path

    get '/page/1'
    assert_equal 'pages#index', @response.body
    assert_equal '1', @request.params[:page]
    assert_equal '/page/1', root_path('1')
    assert_equal '/page/1', root_path(:page => '1')
  end
end