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

class UserMetricsTest < Test::Rails::TestCase
  fixtures :ratings, :comments, :users, :topics, :readings

  @@listables = [:ratings, :rated, :readings]
  
  @@listables.each do |listable|
    define_method("test_list_for_#{listable}_not_explosive") do
      assert_nothing_raised() { User.list_for(listable) }
    end
    
    define_method("test_list_for_#{listable}_returns_five_items") do
      assert_equal(5, User.list_for(listable).length)      
    end
    
    define_method "test_list_for_#{listable}_returns_array" do
      assert_kind_of(Array, User.list_for(listable))
    end

    define_method "test_list_for_#{listable}_returns_array_of_pairs" do
      results = User.list_for(listable)
      results.each {|row| assert_equal(2, row.length) }
      results.each do|user, value|
         assert_kind_of(Numeric, value)
         assert_kind_of(User, user)
      end
    end
    
    define_method "test_list_for_#{listable}_returns_empty_array_when_nothing_found" do
      User.delete_all
      Reading.delete_all
      AbstractRating.delete_all
      assert_kind_of(Array, User.list_for(listable))
    end
    
    define_method "test_list_for_#{listable}_scopped_to_topic" do
      results = User.list_for(listable, :topic => 1)
      assert(results.all?{|u, v|  u.comments.any?{|c| c.topic_id == 1}})
    end
    
  end
  
  def test_list_for_ratings_has_correct_values
    results = User.list_for(:ratings)
    results.each do |user, value|
      all_comment_ratings = user.comments.collect{|c| c.ratings.find(:all, :conditions => 'value !=77')}.flatten
      ratings_sum         = all_comment_ratings.inject(0){|m,r| m + r.value}
      real_ratings_avg    = ratings_sum.to_f / all_comment_ratings.length
      assert_equal(real_ratings_avg, value, "User #{user.id} ratings are off")
    end
  end
  
  def test_list_for_readings_has_correct_values
    results = User.list_for(:readings)
    results.each do |user, value|
      real_reading_count = user.comments.inject(0){|count,c| count + c.readings.count}
      assert_equal(real_reading_count, value, "User #{user.id} readings are off")
    end
  end
  
  def test_list_for_rated_has_correct_values
    results = User.list_for(:rated)
    results.each do |user, value|
      all_comment_rated_count = user.comments.inject(0){|m,c| m+c.ratings.count}
      assert_equal(all_comment_rated_count, value, "User #{user.id} rated is off")
    end
  end
  
  def test_list_for_readings_scopped_to_time
    results = User.list_for(:readings, :max_age => 24)
    assert(results.all? do |u, v|
      u.comments.any? do |c|
        c.readings.any? do |r|
          r.created_at && r.created_at > 24.hours.ago 
        end
      end
    end)
  end
  
  def test_list_for_ratings_scopped_to_time
    results = User.list_for(:ratings, :max_age => 24)
    assert(results.all? do |u, v|
      u.comments.any? do |c|
        c.ratings.any? do |r|
          r.created_on && r.created_on > 24.hours.ago 
        end
      end
    end)
  end
  
  def test_list_for_rated_scopped_to_time
    results = User.list_for(:rated, :max_age => 24)
    assert(results.all? do |u, v|
      u.comments.any? do |c|
        c.ratings.any? do |r|
          r.created_on && r.created_on > 24.hours.ago 
        end
      end
    end)
  end
  
  def test_list_for_rated_reverse
    results = Comment.list_for(:rated, :reverse => true)
    assert_equal(1, results.first[1]) # by value instead of ID since theres a tie
    assert_equal(5, results.last[0].id)
  end
end