<?php
$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
session_start();

require_once dirname(__FILE__) . '/../../../../../../include/chatengine/chatengine.php';
require_once CHEN_DIR.'/chatroom_class.php';
require_once CHEN_DIR.'/chatuser_class.php';
require_once CHEN_DIR.'/transaction.php';
require_once CHEN_DIR.'/transaction/add_room.php';
require_once CHEN_DIR.'/transaction/add_user.php';

//現在はinit.phpへの干渉を最小限にしているため、initを先にロードするとroom_classの依存性が解決できない。
require_once dirname(__FILE__) . '/../../../../../../include/init.php';
$INIT_CONF->LoadClass('ROOM_CONF');
require_once LOCAL_ROOT.'/include/request_class.php';

//-- マルチバイト入出力指定 --//
if(extension_loaded('mbstring')){
  //このコンテキストではグローバル変数に直接アクセスできない。
  //これはテストランナーの関数内でincludeされている場合などに発生しうる。 (2011-01-12 enogu)
  global $SERVER_CONF;
  mb_language('ja');
  mb_internal_encoding($SERVER_CONF->encode);
  mb_http_input('auto');
  mb_http_output($SERVER_CONF->encode);
}

/**
 * Test class for AddUserTransaction.
 * Generated by PHPUnit on 2011-01-01 at 14:57:39.
 */
class AddUserTransactionTest extends PHPUnit_Framework_TestCase {

  /**
   * @var AddUserTransaction
   */
  protected $object;

  protected $_chen;
  public function __get($name) {
    switch($name) {
      case 'chen':
        if (!isset($this->_chen)) {
          $this->_chen = new ChatEngine('localhost', 'jinrou', 'grayran', 'satorituri');
          $this->_chen->beginTransaction();
        }
        return $this->_chen;
    }
  }

  /**
   * Sets up the fixture, for example, opens a network connection.
   * This method is called before a test is executed.
   */
  protected function setUp() {
    $this->object = new AddUserTransaction;
  }

  /**
   * Tears down the fixture, for example, closes a network connection.
   * This method is called after a test is executed.
   */
  protected function tearDown() {
    if (isset($this->_chen)) {
      $this->_chen->rollBack();
    }
    $this->_chen = null;
  }

  /**
   *
   * @dataProvider dp_testGenerateUserNumber
   */
  public function testGenerateUserNumber($max_users, $kicked, $success) {
    //インスタンスの追加
    $add_room = new AddRoomTransaction();
    $room = $add_room->_CreateRoom($this->chen, 'testAddUser', 'ユーザー数の上限テスト', $max_users, '', '');
    //境界値の判定を行うため、事前にユーザーを上限まで登録する。
    for ($i = 0; $i < $max_users; $i++) {
      $user_no = $this->object->_GenerateUserNumber($this->chen, $room->id);
      $this->assertNotSame(false, $user_no);
      //妥当な手段が主いつかなったため力業になっている。可能であれば修正したい(2011-01-19 enogu)
      $uname = "test[{$user_no}]";
      $session_id = md5($uname);
      $sql = <<<SQL
INSERT INTO jinrou_users (room, uname, passwd, session_id, ip_address)
VALUES ({$room->id}, '{$uname}', MD5('testtest'), '{$session_id}', '127.0.0.1')
SQL;
      $this->assertNotSame(false, $this->chen->exec($sql), print_r($this->chen->errorInfo(), true));
      //キックを発生させて空きを作る。
      if ($i < $kicked) {
        $sql = sprintf('UPDATE jinrou_users SET enabled = 0 WHERE id = %d', $this->chen->lastInsertId());
        $this->assertNotSame(false, $this->chen->exec($sql));
      }
    }
    //入村上限のチェック
    $user_no = $this->object->_GenerateUserNumber($this->chen, $room->id);
    if ($success) {
    	$this->assertNotSame(false, $user_no, print_r($this->chen->errorInfo(), true));
        $this->assertEquals($max_users + 1, $user_no);
    }
    else {
    	$this->assertSame(false, $user_no, print_r($this->chen->errorInfo(), true));
    }
  }
  static function dp_testGenerateUserNumber() {
    return array(
        array(10, 0, false),
        array(10, 1, true),
    );
  }

  /**
   * @dataProvider dp_testAddUser
   */
  public function testAddUser($uname, $passwd, $success) {
    //インスタンスの追加
    $add_room = new AddRoomTransaction();
    $room = $add_room->_CreateRoom($this->chen, 'testAddUser', 'ユーザーの追加テスト', 17, '', '');
    $uid = $this->object->_AddUser($this->chen, $room->id, $uname, $passwd);
    //結果の評価
    if ($success) {
      //AddUserTransactionの中間処理では登録済みのidしか返ってこない。
      //インスタンスを取得して入力されたデータを比較する。
      $this->assertNotSame(false, $uid);
      $stmt = $this->chen->prepare('SELECT * FROM jinrou_users WHERE id = :uid');
      $this->assertTrue($stmt->execute(array(':uid' => $uid)));
      $users = $stmt->fetchAll(PDO::FETCH_CLASS, 'ChatUser', array($this->chen));
      $this->assertNotSame(false, $users);
      $this->assertTrue(is_array($users));
      $this->assertEquals(1, count($users));
      $user = $users[0];
      $this->assertType('ChatUser', $user);
      $this->assertEquals($uname, $user->uname);
    }
    else {
      $this->assertSame(false, $uid);
    }
  }
  public static function dp_testAddUser() {
    return array(
        array('test', 'test test', true),
        array('', 'no name', false),
        array('toolong8901234567890223456789032345678904234567890', 'testtest', true),
        array('toolong89012345678902234567890323456789042345678901', 'testtest', false),
        array('no password', '', false),
    );
  }

  /**
   * @dataProvider dp_testAddPlayer
   */
  public function testAddPlayer($user_no, $handle_name, $profile, $sex, $role, $icon_no, $success) {
    //インスタンスの追加
    $add_room = new AddRoomTransaction();
    $room = $add_room->_CreateRoom($this->chen, 'testAddPlayer', 'プレイヤーの追加テスト', 17, '', '');
    $uid = $this->object->_AddUser($this->chen, $room->id, 'testman', 'testman');
    $pid = $this->object->_AddPlayer($this->chen, $uid, $user_no, $handle_name, $profile, $sex, $role, $icon_no);
    //結果の評価(testAddUserと処理の流れはほぼ同じである)
    if ($success) {
      $this->assertNotSame(false, $pid, print_r($this->chen->errorInfo(), true));
      $stmt = $this->chen->query(
        "SELECT * FROM jinrou_users AS usr INNER JOIN jinrou_players AS ply ON usr.id = ply.user WHERE ply.id = {$pid}"
      );
      $users = $stmt->fetchAll(PDO::FETCH_CLASS, 'ChatUser', array($this->chen));
      $this->assertEquals(1, count($users));
      $testman = $users[0];
      $this->assertEquals('testman', $testman->uname);
      $this->assertEquals($user_no, $testman->user_no);
      $this->assertEquals($handle_name, $testman->handle_name);
      $this->assertEquals($profile, $testman->profile);
      $this->assertEquals($sex, $testman->sex);
      $expected_role = $role != '' ? explode(',', $role) : array();
      $this->assertEquals($expected_role, $testman->role);
      $this->assertEquals($icon_no, $testman->icon_no);
    }
    else {
      $this->assertSame(false, $pid, print_r($this->chen->errorInfo(), true));
    }
  }
  public static function dp_testAddPlayer() {
    return array(
        array(1, 'プレイヤー', '成功例', 'male', 'wolf', 1, true),
        array(1, 'プロフィールと役職希望はなくてもエラーにならない', '', 'female', '', 1, true),
        array(0, '不正なユーザー番号', '', 'male', '', 1, false),
        array(-1, '不正なユーザー番号', '', 'male', '', 1, false),
        array(1, '', 'ハンドル名がありません', 'male', '', 1, false),
        array(1, 'toolong8901234567890223456789032345678904234567890', '文字数の上限', 'male', 'wolf,critical', 1, true),
        array(1, 'toolong89012345678902234567890323456789042345678901', '文字数オーバー', 'male', '', 1, false),
        array(1, '性別迷子', '', '', '', 1, false),
        array(1, '性別迷子', '', 'hideyoshi', '', 1, false),
        #array(1, '不正なアイコン番号', '', 'male', '', 0, false), //この数値は身代わり君の時に使用する(2011-01-19 enogu)
        array(1, '不正なアイコン番号', '', 'male', '', -1, false),
    );
  }

  /**
   * @todo Implement test__run().
   * このメソッドはAddRoomTransactionTestの身代わり君の追加処理である程度カバーできる(2011-01-19 enogu)
   */
  public function test__run() {
  }

}

?>
