<?php
// Author: Jacob Redding
// additional tests added by Zhao ning (nzhao, user/96328) 

class UserpointsTestCase extends DrupalWebTestCase {
  /**
   * Implementation of getInfo().
   */
  function getInfo() {
    return array(
      'name' => t('Userpoints API '),
      'description' => t('Tests the core API for proper inserts & updates to the database tables, 
			  moderation, expiration, as well as permission checks'),
      'group' => t('Userpoints'),
    );
  }

  /**
   * Implementation of setUp().
   */
  function setUp() {
    parent::setUp('userpoints');

    // Create an administrator account
    global $admin_user;
    $admin_user = $this->drupalCreateUser(array('administer userpoints'));

    // Create a standard Drupal account and log in as that person
    $non_admin_user = $this->drupalCreateUser();
    $this->drupalLogin($non_admin_user);
  }


  /**
   *
   */
  function testBasicCall() {
    global $user;
    $points = (int) rand(1, 500);
    $sumpoints = $points;

    //NOTE: increment max points with all positive point changes, tests userpoints_get_max_points 
    $maxpoints = $points;

    //Test the a basic API call
    $return = userpoints_userpointsapi($points);
    $this->assertTrue($return['status'] == TRUE , t('API responded with successful grant of points'));

    //Check the database to ensure the point were properly saved
    $sql = "SELECT points from {userpoints_txn} WHERE uid = %d AND points = %d";
    $db_points = (int) db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points === $points, t('Successfully verified points in the txn table'));

    //Check that the transaction table and the summary table match
    $sql = "SELECT SUM(points) FROM {userpoints_txn} WHERE uid = %d";
    $txn_points = (int) db_result(db_query($sql, $user->uid));
    $sql = "SELECT SUM(points) from {userpoints} WHERE uid = %d";
    $up_points = (int) db_result(db_query($sql, $user->uid));
    $this->assertTrue($txn_points === $up_points, t('Sum of transactions match total points for user'));
  
    //Add negative points to the initial value and check the values    
    $points = -rand(1, 500); 
    $sumpoints = $sumpoints + $points; 
    userpoints_userpointsapi($points); 
   
    //Check the database to ensure the negative point value was properly saved
    $sql = "SELECT points from {userpoints_txn} WHERE uid = %d AND points = %d";
    $db_points = (int) db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points === $points, t('Successfully verified negative points in the txn table'));


    //Now test to make sure the transaction and and caching table stay in sync. 
    //Also test userpoints_get_max_points and userpoints_get_current_points
    for($i = 0; $i <= rand(1,50); $i++) {
      $points = rand(1, 500); 
      if (rand() & 1) {
        $points = - $points; 
      }
	    
	  if ($points > 0) { 
	    $maxpoints = $maxpoints + $points;	
	  }
      $sumpoints = $sumpoints + $points;
      userpoints_userpointsapi($points);       
    } 


    //Check the summary table to make sure everything is still kosher. 
    $sql = "SELECT SUM(points) FROM {userpoints_txn} WHERE uid = %d";
    $txn_points = (int) db_result(db_query($sql, $user->uid));
   
    $sql = "SELECT SUM(points) from {userpoints} WHERE uid = %d";
    $up_points = (int) db_result(db_query($sql, $user->uid));

    $this->assertTrue($txn_points === $up_points, t('Sum of transactions matches the caching table'));    
    $this->assertTrue($up_points === $sumpoints, 
                       t('Caching table matches testing code after !recs point records totaling !points points', 
                          array('!recs' => $i, '!points' => $sumpoints ))
                     );        
    $this->assertTrue($sumpoints == userpoints_get_current_points(), 
					  t("userpoints_get_current_points() returned correct point value")
					 );
    $this->assertTrue($maxpoints == userpoints_get_max_points(), 
					  t("userpoints_get_max_points() returned correct point value")
					 );

  } 


  /**
   *
   */
  function testParamsArrayCall() {
    global $user;
    global $admin_user;

    $points = rand(); 
   
      //Assert that the use of a params array with simply points in it works. 
    $params = array(
	    'points' => $points,
    );
 
    $this->assertTrue(userpoints_userpointsapi($params) == TRUE, 
		     t('API call using a params array responded with successful grant of points')
		     );

      //Check the Database to make sure the points made it there 
    $sql = "SELECT points from {userpoints_txn} WHERE uid = %d AND points = %d";
    $db_points = db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points == $points, t('Successfully verified points in the txn table'));

      //Test to ensure that calling it with no points returns false indicating an error
    $params = array(
	    'points' => '',
	  );

    $return = userpoints_userpointsapi($params);
    $this->assertTrue($return['status'] == FALSE, 
                      t('API successfully prevented null points from being added'));

    $params = array(
	  'points' => 'abcd',
    );
    $return = userpoints_userpointsapi($params);
    $this->assertTrue($return['status'] == FALSE, 
		      t('API successfully prevented non-numeric points from being added')
		     );


    //Award points to admin user and test to ensure they were awarded to the correct user
    $params = array(
	  'points' => $points,
	  'uid' => $admin_user->uid,
    );
 
    $this->assertTrue(userpoints_userpointsapi($params) == TRUE, 
		     t('Successfully granted points to admin user')
		     );

      //Check the Database to make sure the points made it there 
    $sql = "SELECT points from {userpoints_txn} WHERE uid = %d AND points = %d";
    $db_points = db_result(db_query($sql, $admin_user->uid, $points));
    $this->assertTrue($db_points == $points, t('Successfully verified points in the txn table'));

   
    //Attempt to award points to a non-existent user 
    $sql = "SELECT uid FROM {users} ORDER BY uid DESC LIMIT 1"; 
    $nonuid = db_result(db_query($sql)) +1;
    $params = array(
	  'points' => $points,
	  'uid' => $nonuid,
    );
 
    $ret = userpoints_userpointsapi($params);
    $this->assertTrue($ret['status'] == FALSE, 
		     t('Successfully blocked points given to a non-existent user')
		     );

    //attempt to award points to a non-existent term
    $maxtid = "SELECT tid from {term_data} ORDER BY tid DESC LIMIT 1";
    $nontid =  db_result(db_query($sql)) +1;
    $params = array(
	  'points' => $points,
	  'uid' => $nontid,
    );

    $ret = userpoints_userpointsapi($params);
    $this->assertTrue($ret['status'] == FALSE, 
		     t('Successfully blocked points given to a non-existent tid')
		     );

    //Test various aspects of the API to ensure the DB is being updated successfully 
   $points = rand(1,500);
   $description = $this->randomName();
   $operation = $this->randomName();
   $params = array(
     'points' => $points,
     'description' => $description,
     'operation' => $operation
   );

   $ret = userpoints_userpointsapi($params);
   $sql =  "SELECT description, operation, reference FROM {userpoints_txn} WHERE description = '%s' AND operation = '%s'";
   $db_point_rec = db_fetch_array(db_query($sql, $description, $operation));
   $this->assertTrue($db_point_rec['description'] == $description, t('Point description successfully verified in DB'));
   $this->assertTrue($db_point_rec['operation'] == $operation, t('Point event successfully verified in DB'));
  }
 

  function testExpiration() {
    global $user;

    //clear the table before we begin
	  db_query("TRUNCATE TABLE {userpoints}");
    db_query("TRUNCATE TABLE {userpoints_txn}");
		$points = rand(1, 100);
		$sum_points = 0; 

		//Create various time tests
		$times['valid']['time'] = rand(1, 10000);
		$times['valid']['string'] = '(expirydate = random number)'; 
		$times['expire']['time'] = time();
		$times['expire']['string'] = '(expirydate = today)';	
		$times['null']['time'] = NULL;
		$times['null']['string'] = '(expirydate = NULL)';
		
		$bad_time = 'test string';
		  //First lets check to make sure it is blocking bad times
		$params = array (
			'uid' => $user->uid,
			'points' => $points,
			'expirydate' => $bad_time,
	  );
		$return = userpoints_userpointsapi($params);
		$this->assertTrue($return['status'] == FALSE, 
			t(print_r($return, TRUE) ."API succesfully blocked an entry with a string as the expiry date"));


    foreach($times as $time) {
			$params = array (
				'uid' => $user->uid,
				'points' => $points,
				'expirydate' => $time['time'],
				);
			$return = userpoints_userpointsapi($params);
			$this->assertTrue($return['status'] == TRUE, 
				t($time['string'] ." API responded with a successful grant of points"));
			/* Check the database to ensure the points were properly saved */
			$sql = "SELECT points FROM {userpoints_txn} WHERE uid = %d AND points = %d AND expirydate = %d";
			$db_points = (int) db_result(db_query($sql, $user->uid, $points, $time['time']));
			$this->assertTrue($db_points == $points,
				t($time['string'] ."Successfully verified points in the txn table.") );
      if ($db_points == $points) {
	      $sum_points = $sum_points + $points; 
      }

			/* Check update point to 'userpoints' table */
			$sql1 = "SELECT points FROM {userpoints} WHERE uid=%d";
			$db_points = (int) db_result(db_query($sql1, $user->uid));
			$this->assertTrue($db_points == $sum_points,
				t($time['string'] ."Successfully verified that the summary table was updated") );
    }

    //clear the slate again
	  db_query("TRUNCATE TABLE {userpoints}");
    db_query("TRUNCATE TABLE {userpoints_txn}");
  
    //Add two different points in, one to post immediately another to expire in the future. 
    $keep_points = rand(1,100);
    $expire_points = rand(1,100);
		$params = array (
			'uid' => $user->uid,
			'points' => $expire_points,
			'expirydate' => time() - 1000,
			);
		$return = userpoints_userpointsapi($params);
		$this->assertTrue($return['status'] == TRUE, 
				t("API succesfully added points for expiration"));

		$params = array (
			'uid' => $user->uid,
			'points' => $keep_points,
			'expirydate' => time() + 10000,
			);
    userpoints_userpointsapi($params);
		$this->assertTrue($return['status'] == TRUE, 
				t("API succesfully added points for expiration"));

    /* Call cron to check expiration */
    userpoints_cron();

    /* Check the user points removed or not if the point was expiration */
    $sql = "SELECT SUM(points) FROM {userpoints_txn} WHERE uid = %d";
    $db_points = (int) db_result(db_query($sql, $user->uid));
    $this->assertTrue($db_points == $keep_points,t("Successfully removed expired points from the txn table.") );

    $sql = "SELECT points FROM {userpoints} WHERE uid=%d";
    $db_points = (int) db_result(db_query($sql, $user->uid));
    $this->assertTrue($db_points == $keep_points,t("Successfully removed expired points from the summary table.") );
  }

  /*
   * Changes the default expiration date in the administrative settings 
   * and then checks to ensure that it is saved/returned correctly. 
  */
  function test_get_default_expiry_date() {
	   //login as an admin
    global $admin_user; 
	  $this->drupalLogin($admin_user);  
	
    $date = mktime(0, 0, 0, 1, 1, 2010);

    /* save settings */
    $edit = array (
      'userpoints_points_moderation' => '1',
      'userpoints_trans_ucpoints' => 'Points',
      'userpoints_trans_lcpoints' => 'points',
      'userpoints_trans_lcpoint' => 'point',
      'userpoints_trans_uncat' => 'Uncategorized',
      'userpoints_expireafter_date' => '2419200',
      'userpoints_expireon_date[month]' => '1',
      'userpoints_expireon_date[day]' => '1',
      'userpoints_expireon_date[year]' => '2010',
      'userpoints_expiry_description' => '',
      'userpoints_display_message' => '1',
      'userpoints_report_limit' => '10',
      'userpoints_report_displayzero' => '1',
      'userpoints_report_usercount' => '30',
      'userpoints_category_default_tid' => '0',
    );
    $this->drupalPost('admin/settings/userpoints', $edit, 'Save configuration');

    /* check database */
    $sql = "SELECT value FROM {variable} WHERE name='%s'";
    $expireon_date = db_result(db_query($sql, 'userpoints_expireon_date'));
    $this->assertTrue($expireon_date != false, t("Successfully verified the expiriation date in the database."));

    /* check API */
    $expiry_date = userpoints_get_default_expiry_date();
    $this->assertTrue($expiry_date == $date, t("Successfully verified that userpoints_get_expiry_date returns correct date is %s.", array('%s'=>date("M-d-Y", $expiry_date))));
  }


  function testGetDefaultTid () {
    $vid = userpoints_get_vid();
    $term_name = $this->randomName(10);
    $desc = $this->randomName(10);

    /* create a new term*/
    $new_term = array(
      'name' => $term_name,
      'description' => $desc,
      'vid' => $vid
    );
    taxonomy_save_term($new_term);

    /* get this term */
    $term = taxonomy_get_term_by_name($term_name);

    /* login as admin userpoints */
    $admin_user = $this->drupalCreateUser(array('administer userpoints'));
    $this->drupalLogin($admin_user);

    /* save settings */
    $edit = array (
      'userpoints_points_moderation' => '1',
      'userpoints_trans_ucpoints' => 'Points',
      'userpoints_trans_lcpoints' => 'points',
      'userpoints_trans_lcpoint' => 'point',
      'userpoints_trans_uncat' => 'Uncategorized',
      'userpoints_expireafter_date' => '2419200',
      'userpoints_expireon_date[month]' => '1',
      'userpoints_expireon_date[day]' => '1',
      'userpoints_expireon_date[year]' => '2010',
      'userpoints_expiry_description' => '',
      'userpoints_display_message' => '1',
      'userpoints_report_limit' => '10',
      'userpoints_report_displayzero' => '1',
      'userpoints_report_usercount' => '30',
      'userpoints_category_default_tid' => $term[0]->tid,
    );
    $this->drupalPost('admin/settings/userpoints', $edit, 'Save configuration');

    /* check database */
    $sql = "SELECT value FROM {variable} WHERE name='%s'";
    $expireon_date = db_result(db_query($sql, 'userpoints_category_default_tid'));
    $this->assertTrue($expireon_date != false, t("Successfully verified the term ID in the database."));

    /* check API*/
    $tid = userpoints_get_default_tid();
    $this->assertTrue($tid == 0, t("Successfully retrieved default tid = %d.", array('%d'=>$tid)));

    /* check database */
    $sql = "SELECT value FROM {variable} WHERE name='%s'";
    $expireon_date = db_result(db_query($sql, 'userpoints_category_default_vid'));
    $this->assertTrue($expireon_date != false, t("Successfully verified the vocab ID in the database."));

    /* check API*/
    $vid = userpoints_get_vid();
    $this->assertTrue(is_numeric($vid), t("Successfully retrieved default vid %d.", array('%d'=>$vid)));
  }
  /**
   * Test user permissions
   */
  function testUserpermissions () {
    $username = 'test';
    $points = 10;

    /** check permission with admin user **/
    $admin_user = $this->drupalCreateUser(array('administer userpoints'));
    $this->drupalLogin($admin_user);

    /*check access page*/
    $this->drupalGet('admin/user/userpoints');
    $content = $this->drupalGetContent();
    $content = strstr($content, 'Access denied');
    $this->assertTrue($content == false, t("Successful navigated to the page modify points"));

    /* check modify points */
    $edit = array (
      'txn_user' => $admin_user->name,
      'points' => $points,
    );
    $this->drupalPost('admin/user/userpoints/add', $edit, 'Save');

    /* check database */
    $sql = "SELECT points FROM {userpoints_txn} WHERE uid=%d AND points=%d";
    $db_points = (int)db_result(db_query($sql, $admin_user->uid, $points));
    $this->assertTrue($db_points == $points, t("Successful verified that points were added into database."));

    /* logout and change user */
    $this->drupalLogout();

    /* check permission with view user */
    $view_user = $this->drupalCreateUser(array('view userpoints'));
    $this->drupalLogin($view_user);

    /*check access page*/
    $this->drupalGet('admin/user/userpoints');
    $content = $this->drupalGetContent();
    $content = strstr($content, 'Access denied');
    $this->assertTrue(is_string($content), t("Successful verified that a user without admin userpoints permissions can not modify points."));

    /* check modify points */

   //This part of the test should be enabled and it ensures that a POST 
   //won't add points (regardless of what the HTML says). If it is uncommented
   //it will throw errors because the POST fields don't exist (which is good). 
/*
    $edit = array (
      'txn_user' => $view_user->name,
      'points' => $points,
    );
    $this->drupalPost('admin/user/userpoints/add', $edit, 'Save');
*/

    /* check database */
    $sql = "SELECT points FROM {userpoints_txn} WHERE uid=%d AND points=%d";
    $db_points = (int)db_result(db_query($sql, $view_user->uid, $points));
    $this->assertTrue($db_points != $points, t("Successful verified that points do not add into database."));
    $this->drupalLogout();
  }

  function testModeration() {
    global $user;
    $points = rand(1, 100);

    /** condition1 moderate=true **/
    $params = array (
      'uid' => $user->uid,
      'points' => $points,
      'moderate' => true,
    );
    /* add points to user */
    $return = userpoints_userpointsapi($params);
    $this->assertTrue($return['status'] == TRUE , t("1. (moderate=true) API responded with successful grant of points"));

    /* Check the database to ensure the point were properly saved */
    $sql = "SELECT points FROM {userpoints_txn} WHERE uid = %d AND points = %d AND status = 1";
    $db_points = (int) db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points == $points,t("1. (moderate=true) Successfully verified points in the txn table and waiting moderation.") );

    /* Check do not update point to 'userpoints' table */
    $sql1 = "SELECT points FROM {userpoints} WHERE uid=%d";
    $db_points = (int) db_result(db_query($sql1, $user->uid));
    $this->assertTrue($db_points == 0,t("1. (moderate=true) Successfully verified that points were added and the summary table was not updated.") );


/*
    //DISABLED because it should be checking if it adhered to the sites default moderation status
    $params = array (
      'uid' => $user->uid,
      'points' => $points,
      'moderate' => NULL,
    );
    $return = userpoints_userpointsapi($params);
    $this->assertTrue($return['status'] == TRUE , t("6. (moderate=NULL) API responded with successful grant of points"));

    $sql = "SELECT points FROM {userpoints_txn} WHERE uid = %d AND points = %d AND status = 1";
    $db_points = (int) db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points == $points,t("6. (moderate=NULL) Successfully verified points in the txn table and waiting moder.") );

    $sql1 = "SELECT points FROM {userpoints} WHERE uid=%d";
    $db_points = (int) db_result(db_query($sql1, $user->uid));
    $this->assertTrue($db_points == 0,t("6. (moderate=NULL) Successfully, Points added and does not modify summary table.") );

*/

    /** condition7 moderate=false **/
    $params = array (
      'uid' => $user->uid,
      'points' => $points,
      'moderate' => false,
    );
    /* add points to user */
    $return = userpoints_userpointsapi($params);
    $this->assertTrue($return['status'] == TRUE , t("7. (moderate=false) API responded with successful grant of points"));

    /* Check the database to ensure the point were properly saved */
    $sql = "SELECT points FROM {userpoints_txn} WHERE uid = %d AND points = %d AND status = 0";
    $db_points = (int) db_result(db_query($sql, $user->uid, $points));
    $this->assertTrue($db_points == $points,t("7. (moderate=false) Successfully verified points in the txn table and NOT waiting moderation.") );
  }


  /**
   *
   */
  function testGetCategories() {
	  $cats = userpoints_get_categories();
	  $this->assertTrue(is_array($cats), 'Successfully verified userpoints_get_categories() returned an array');
  }


}

