require File.dirname(__FILE__) + '/../test_helper'

class RegisteredUserTest < Test::Rails::TestCase
  fixtures :users, :comments, :support_materials, :readings, :ratings, :registration_filter_items, :topics
  
  def test_should_create_user
    assert create_user.valid?
  end

  def test_should_require_email
    u = create_user(:email => nil)
    assert u.errors.on(:email)
  end

  def test_should_require_password
    u = create_user(:password => nil)
    assert u.errors.on(:password)
  end

  def test_should_require_password_confirmation
    u = create_user(:password => 'foobar', :password_confirmation => nil)
    assert u.errors.on(:password_confirmation), "should be invalid missing password_confirmation"
  end

  def test_should_require_valid_email
    u = create_user(:email => '@123.23')
    assert u.errors.on(:email)
  end

  def test_should_reset_password
    users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password')
    assert_equal users(:quentin), RegisteredUser.authenticate('quentin@example.com', 'new password')
  end

  def test_should_not_rehash_password
    assert users(:quentin).update_attributes(:email => 'quentin2@example.com'), "email update failed, " + users(:quentin).errors.full_messages.join(', ')
    assert_equal users(:quentin), RegisteredUser.authenticate('quentin2@example.com', 'quentin')
  end

  def test_should_authenticate_user
    assert_equal users(:quentin), RegisteredUser.authenticate('quentin@example.com', 'quentin')
  end

  
  def test_users_have_comments
    create_fixtures :comments
    assert users(:ernest).comments
    assert_equal 2, users(:ernest).comments.count
  end
  
  def test_user_number_taken_eh
    assert RegisteredUser.user_number_taken?(users(:ernest).user_number)
    assert !RegisteredUser.user_number_taken?(392109)
  end


  def test_take_activity_from_guest_account_destroys_guest_account
    assert_difference(User, :count, '', -1) do
      users(:frank).take_activity_from_guest_account!(users(:visitor1))
    end
    assert_record_not_found(User, users(:visitor1).id)
  end
  
  def test_take_activity_from_guest_account_does_not_move_ratings
    assert_difference(Reading, :count, '', -3) do
      assert_difference(AbstractRating, :count, '', -1) do
        users(:frank).take_activity_from_guest_account!(users(:visitor1))
      end
    end
  end
  
  def test_take_activity_from_guest_account_does_not_destroy_non_guest
    assert_no_difference(User, :count) do
      users(:frank).take_activity_from_guest_account!(users(:laura))
    end
  end
  
  def test_authenticate_should_fail_unverified_user
    u = users(:quentin)
    u.update_attribute(:verified, false)
    assert !RegisteredUser.authenticate(u.email, u.password) 
  end


  def test_after_create_should_set_user_login_key
    joe = create_user
    assert joe.login_key, "login key is missing"
    assert !joe.login_key.blank?, "login key is blank"
  end
  
  def test_updating_user_with_nil_salt_should_not_raise_exception
    frank = users(:frank)
    valid_attributes = {
      "name"=>"Frank", 
      "password_confirmation"=>"silly", 
      "picture"=>"",
      "password"=>"silly", 
      "email"=>"frank@omara.ca"
    }
    assert_nothing_raised do 
      frank.update_attributes(valid_attributes)
    end
  end
  
  def test_update_average_rating_cache
    @user = users(:laura)
    @user.logger.info "original rating #{@user.avg_rating}"
    @user.rateds.first.update_attribute(:value, 1) # can just create new rating, since that would trigger it's callback
    @user.update_average_rating_cache
    assert_in_delta(1.6, @user.avg_rating, 0.1) 
  end
  
  def test_find_ten_best_avg_rating
    assert_nothing_raised { RegisteredUser.find_ten_best_avg_rating }
    assert RegisteredUser.find_ten_best_avg_rating.is_a?(Array)
    assert_equal users(:grace), RegisteredUser.find_ten_best_avg_rating.first
  end
  
  def test_find_ten_best_avg_rating_only_values_GT_zero
    RegisteredUser.find_ten_best_avg_rating.each do |u|
      assert u.avg_rating > 0, "Rating for %s is %s" % [u.email, u.avg_rating.inspect]
    end
    assert !RegisteredUser.find_ten_best_avg_rating.include?(users(:arthur)) # arthur has avg_rating 0
  end
  
  def test_find_ten_best_avg_rating_excludes_nil
    assert !RegisteredUser.find_ten_best_avg_rating.include?(users(:quentin)) # quentin has avg_rating nil
  end
  
  def test_user_can_be_suspended
    assert_respond_to(RegisteredUser.new, :suspended?)
  end
  
  def test_users_default_not_suspended
    assert !RegisteredUser.new.suspended?
  end
  
  def test_suspended_user_cannot_login  
    sally = users(:suspended_sally)
    assert !RegisteredUser.authenticate(sally.email, sally.password)
  end
  
  def test_class_suspended_eh
    assert RegisteredUser.suspended?(users(:suspended_sally).email)
    assert !RegisteredUser.suspended?(users(:ernest).email)
  end
  
  def test_accessible_topic_ids
    create_fixtures :access_passes
    assert_equal([1,2], users(:ernest).accessible_topic_ids)
    assert_equal([], users(:quentin).accessible_topic_ids)
  end

  def test_commented_topics_does_not_reveal_private_topics
    fourth  = topics(:fourth)
    quentin = users(:quentin)
    User.logger.info fourth.comments.count.to_s
    sanity_check(fourth.comments.count > 0, "Fourth has comments")
    sanity_check(fourth.private?, "Fourth is private")
    sanity_check(!quentin.accessible_topic_ids.include?(fourth.id), "Quentin does not have access to Fourth")
    
    topics_with_comments_by_laura = quentin.commented_topics_by(users(:laura))
    assert !topics_with_comments_by_laura.any?{|topic, comments| topic == fourth}, "Private topic 'Fourth' found among #{topics_with_comments_by_laura.inspect}"
  end
  
  protected
  
  def create_user(options = {})
    RegisteredUser.create({ :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
  end
  
end
