require File.expand_path(File.dirname(__FILE__) + "/../../test_helper")

class Admin::UsersIntegrationTest < ActionController::IntegrationTest
  def setup
    @user = User.find_or_create_by_username 'betty'
    @user.update_attribute :password, 'crocker'
  end
  
  def test_create
    post("/admin/users", :user => { :username => 'bill', :password => '' })
    
    # should assign a new random password
    user = User.find_by_username 'bill'
    assert_not_nil(user)
    assert_not_equal(user.password, '')
  end
  
  def test_create_with_the_same_username
    @user_count = User.count
    post("/admin/users", :user => {:username => 'betty', :password => ''})
    
    # should not save a new user
    assert_equal(User.count, @user_count)
    
    # should not call after_save
    assert_response :success
  end
  
  def test_destroy
    delete "/admin/users/#{@user.id}"
    
    # should destroy the user
    assert_nil(User.find_by_id(@user.id))
  end
  
  def test_edit
    @user.update_attributes(:force_blog_posts_to_textile => true)
    get "/admin/users/#{@user.id}/edit"
    
    # should show the default text input for password
    assert_match(%r|<input[^>]*name="user\[password\]"|, response.body)
    
    # should show a reset password checkbox
    assert_select("input[type=checkbox][name=reset_password]")
    
    # should show a drop-down for force_blog_posts_to_textile
    assert_select('select[name=?]', 'user[force_blog_posts_to_textile]') do
      assert_select "option:not([selected])[value='']"
      assert_select "option:not([selected])[value=0]", :text => 'false'
      assert_select "option[selected=selected][value=1]", :text => 'true'
    end
  end
  
  def test_index
    get "/admin/users"
    
    # should show a Delete link and a link to the profile page
    assert_select('td') do
      assert_select(
        "a.destroy[href=?][data-method=?]",
        "/admin/users/#{@user.id}", 'delete',
        :text => 'Delete'
      )
      assert_select(
        "a[href=?]",
        "/admin/blog_posts/new?blog_post[user_id]=#{@user.id}",
        :text => "New blog post"
      )
    end
  end
  
  def test_index_search
    User.destroy_all
    @john_doe = User.create! :username => 'johndoe'
    @jane_doe = User.create! :username => 'janedoe', :password => "ihatejohn"
    get "/admin/users", :search => "john"
    assert_response :success
    
    # should match username
    assert_select('td', :text => 'johndoe')
    
    # should not match password
    assert_no_match(%r|<td[^>]*>janedoe</td>|, response.body)
  end
  
  def test_index_search_across_first_name_and_last_name
    User.destroy_all
    @john_doe = User.create!(
      :username => 'johndoe', :first_name => 'john', :last_name => 'doe'
    )
    get "/admin/users", :search => "john doe"
    
    # should match
    assert_select('td', :text => 'johndoe')
  end
  
  def test_new
    get "/admin/users/new"
    
    # should not show an input for password
    assert_match(/autogenerated/, response.body)
    assert_no_match(%r|<input[^>]*name="user\[password\]"|, response.body)
    
    # should not show a reset password checkbox
    assert_select("input[type=checkbox][name=reset_password]", false)
    
    # should use date dropdowns with nil defaults for birthday
    nums_and_dt_fields = {1 => :year, 2 => :month, 3 => :day}
    nums_and_dt_fields.each do |num, dt_field|
      name = "user[birthday(#{num}i)]"
      assert_select('select[name=?]', name) do
        assert_select "option[value='']"
        assert_select(
          "option:not([selected])[value=?]", Time.now.send(dt_field).to_s
        )
      end
    end
    
    # should not try to set an hour or minute for birthday
    nums_and_dt_fields = {4 => :hour, 5 => :min}
    nums_and_dt_fields.each do |num, dt_field|
      name = "blog_post[published_at(#{num}i)]"
      assert_select('select[name=?]', name, false)
    end
    
    # should respect start_year and end_year parameters
    assert_select("select[name='user[birthday(1i)]']") do
      (Time.now.year-100).upto(Time.now.year) do |year|
        assert_select "option[value='#{year}']"
      end
    end
    
    # should show a drop-down for US states
    assert_select('select[name=?]', 'user[state]') do
      assert_select "option[value='']"
      assert_select "option:not([selected])[value=AK]", :text => 'Alaska'
      assert_select "option:not([selected])[value=NY]", :text => 'New York'
      # blank option, 50 states, DC, Puerto Rico == 53 options
      assert_select "option", :count => 53
    end
    
    # should show a drop-down for force_blog_posts_to_textile
    assert_select('select[name=?]', 'user[force_blog_posts_to_textile]') do
      assert_select "option[value='']"
      assert_select "option:not([selected])[value=0]", :text => 'false'
      assert_select "option:not([selected])[value=1]", :text => 'true'
    end
    
    # should show a select for admin_level
    assert_select("select[name=?]", "user[admin_level]") do
      assert_select("option[value='']", false)
      assert_select "option[value=normal][selected=selected]"
      assert_select "option[value=admin]"
      assert_select "option[value=superuser]"
    end
  end
  
  def test_update
    put(
      "/admin/users/#{@user.id}",
      :user => {:username => 'bettie', :force_blog_posts_to_textile => ''}
    )
    @user.reload
  
    # should not assign a new random password
    assert_equal(@user.password, 'crocker')
  
    # should know the difference between nil and false for force_blog_posts_to_textile
    assert_nil(@user.force_blog_posts_to_textile)
  end
  
  def test_update_while_resetting_password
    put(
      "/admin/users/#{@user.id}",
      :user => {:username => 'bettie'}, :reset_password => '1'
    )
    
    # should assign a new random password
    @user.reload
    assert_not_equal(@user.password, 'crocker')
  end
end
