require 'abstract_unit'
require 'controller/fake_controllers'
require 'active_support/core_ext/object/with_options'

module ActionPack
  class URLForIntegrationTest < ActiveSupport::TestCase
    include RoutingTestHelpers
    include ActionDispatch::RoutingVerbs

    Model = Struct.new(:to_param)

    Mapping = lambda {
      namespace :admin do
        resources :users, :posts
      end

      namespace 'api' do
        root :to => 'users#index'
      end

      get '/blog(/:year(/:month(/:day)))' => 'posts#show_date',
        :constraints => {
          :year => /(19|20)\d\d/,
          :month => /[01]?\d/,
          :day => /[0-3]?\d/
        },
        :day => nil,
        :month => nil

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

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

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

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

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

      ActiveSupport::Deprecation.silence {
        get 'comment/:id(/:action)' => "comments#show"
        get 'ws/:controller(/:action(/:id))', :ws => true
        get 'account(/:action)' => "account#subscription"
        get 'pages/:page_id/:controller(/:action(/:id))'
        get ':controller/ping', :action => 'ping'
        get ':controller(/:action(/:id))(.:format)'
      }

      root :to => "news#index"
    }

    attr_reader :routes
    attr_accessor :controller

    def setup
      @routes = make_set false
      @routes.draw(&Mapping)
    end

    [
      ['/admin/users',[ { :use_route => 'admin_users' }]],
      ['/admin/users',[ { :controller => 'admin/users' }]],
      ['/admin/users',[ { :controller => 'admin/users', :action => 'index' }]],
      ['/admin/users',[ { :action => 'index' }, { :controller => 'admin/users', :action => 'index' }, '/admin/users']],
      ['/admin/users',[ { :controller => 'users', :action => 'index' }, { :controller => 'admin/accounts', :action => 'show', :id => '1' }, '/admin/accounts/show/1']],
      ['/people',[      { :controller => '/people', :action => 'index' }, {:controller=>"admin/accounts", :action=>"foo", :id=>"bar"}, '/admin/accounts/foo/bar']],

      ['/admin/posts',[     { :controller => 'admin/posts' }]],
      ['/admin/posts/new',[ { :controller => 'admin/posts', :action => 'new' }]],

      ['/blog/2009',[     { :controller => 'posts', :action => 'show_date', :year => 2009 }]],
      ['/blog/2009/1',[   { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1 }]],
      ['/blog/2009/1/1',[ { :controller => 'posts', :action => 'show_date', :year => 2009, :month => 1, :day => 1 }]],

      ['/archive/2010',[ { :controller => 'archive', :action => 'index', :year => '2010' }]],
      ['/archive',[      { :controller => 'archive', :action => 'index' }]],
      ['/archive?year=january',[ { :controller => 'archive', :action => 'index', :year => 'january' }]],

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

      ['/id_default/2',[ { :controller => 'foo', :action => 'id_default', :id => '2' }]],
      ['/id_default',[   { :controller => 'foo', :action => 'id_default', :id => '1' }]],
      ['/id_default',[   { :controller => 'foo', :action => 'id_default', :id => 1 }]],
      ['/id_default',[   { :controller => 'foo', :action => 'id_default' }]],
      ['/optional/bar',[ { :controller => 'posts', :action => 'index', :optional => 'bar' }]],
      ['/posts',[ { :controller => 'posts', :action => 'index' }]],

      ['/project',[    { :controller => 'project', :action => 'index' }]],
      ['/projects/1',[ { :controller => 'project', :action => 'index', :project_id => '1' }]],
      ['/projects/1',[ { :controller => 'project', :action => 'index'}, {:project_id => '1', :controller => 'project', :action => 'index' }, '/projects/1']],
      ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index', :project_id => '1' }]],
      ['/projects/1',[ { :use_route => 'project', :controller => 'project', :action => 'index' }, { :controller => 'project', :action => 'index', :project_id => '1' }, '/projects/1']],

      ['/clients',[ { :controller => 'projects', :action => 'index' }]],
      ['/clients?project_id=1',[ { :controller => 'projects', :action => 'index', :project_id => '1' }]],
      ['/clients',[ { :controller => 'projects', :action => 'index' }, { :project_id => '1', :controller => 'project', :action => 'index' }, '/projects/1']],

      ['/comment/20',[   { :id => 20 }, { :controller => 'comments', :action => 'show' }, '/comments/show']],
      ['/comment/20',[   { :controller => 'comments', :id => 20, :action => 'show' }]],
      ['/comments/boo',[ { :controller => 'comments', :action => 'boo' }]],

      ['/ws/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1', :ws => true }]],
      ['/ws/posts',[        { :controller => 'posts', :action => 'index', :ws => true }]],

      ['/account',[         { :controller => 'account', :action => 'subscription' }]],
      ['/account/billing',[ { :controller => 'account', :action => 'billing' }]],

      ['/pages/1/notes/show/1',[ { :page_id => '1', :controller => 'notes', :action => 'show', :id => '1' }]],
      ['/pages/1/notes/list',[   { :page_id => '1', :controller => 'notes', :action => 'list' }]],
      ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes', :action => 'index' }]],
      ['/pages/1/notes',[ { :page_id => '1', :controller => 'notes' }]],
      ['/notes',[         { :page_id => nil, :controller => 'notes' }]],
      ['/notes',[         { :controller => 'notes' }]],
      ['/notes/print',[   { :controller => 'notes', :action => 'print' }]],
      ['/notes/print',[   {}, { :controller => 'notes', :action => 'print' }, '/notes/print']],

      ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :action => 'index', :id => '1' }, '/notes/index/1']],
      ['/notes/index/1',[ { :controller => 'notes' }, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']],
      ['/notes/index/1',[ { :action => 'index' }, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']],
      ['/notes/index/1',[ {}, { :controller => 'notes', :id => '1', :action => 'index' }, '/notes/index/1']],
      ['/notes/show/1',[  {}, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']],
      ['/posts',[      { :controller => 'posts' }, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']],
      ['/notes/list',[ { :action => 'list' }, { :controller => 'notes', :action => 'show', :id => '1' }, '/notes/show/1']],

      ['/posts/ping',[    { :controller => 'posts', :action => 'ping' }]],
      ['/posts/show/1',[  { :controller => 'posts', :action => 'show', :id => '1' }]],
      ['/posts/show/1',[  { :controller => 'posts', :action => 'show', :id => '1', :format => '' }]],
      ['/posts',[         { :controller => 'posts' }]],
      ['/posts',[         { :controller => 'posts', :action => 'index' }]],
      ['/posts/create',[  { :action => 'create' }, {:day=>nil, :month=>nil, :controller=>"posts", :action=>"show_date"}, '/blog']],
      ['/posts?foo=bar',[ { :controller => 'posts', :foo => 'bar' }]],
      ['/posts?foo%5B%5D=bar&foo%5B%5D=baz', [{ :controller => 'posts', :foo => ['bar', 'baz'] }]],
      ['/posts?page=2',  [{ :controller => 'posts', :page => 2 }]],
      ['/posts?q%5Bfoo%5D%5Ba%5D=b', [{ :controller => 'posts', :q => { :foo => { :a => 'b'}} }]],

      ['/news.rss', [{ :controller => 'news', :action => 'index', :format => 'rss' }]],
    ].each_with_index do |(url, params), i|
      if params.length > 1
        hash, path_params, route = *params
        hash[:only_path] = true

        define_method("test_#{url.gsub(/\W/, '_')}_#{i}") do
          get URI('http://test.host' + route.to_s)
          assert_equal path_params, controller.request.path_parameters
          assert_equal url, controller.url_for(hash), params.inspect
        end
      else
        define_method("test_#{url.gsub(/\W/, '_')}_#{i}") do
          assert_equal url, url_for(@routes, params.first), params.inspect
        end
      end
    end
  end
end
