<?php
/**
 * This file contains the PMO_Dbms_Mysqli driver tests.
 *
 * This file is part of the PhpMyObject project,
 * an Object-Relational Mapping (ORM) system.
 * 
 * For questions, help, comments, discussion, etc., please join our
 * forum at {@link http://www.developpez.net/forums/forumdisplay.php?f=770} 
 *
 * PhpMyObject is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see {@link http://www.gnu.org/licenses/}.
 *
 * @package			PhpMyObject
 * @subpackage		PMO_Tests
 * @author			Louis Lapointe <laplix@gmail.com>
 * @link				http://pmo.developpez.com/
 * @since			v0.15
 * @version			$Revision$
 * @copyright		Copyright (C) 2008 Louis Lapointe
 * @license			GPLv3 {@link http://www.gnu.org/licenses/gpl}
 * @filesource
 *
 */ 

/**
 * setup this test case if called individually
 */
if (!defined('PMO_TEST_SUITE')) {
	require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'config.php');
	require_once(SIMPLETEST.DS.'autorun.php');
}


/**
 * requires the PMO_Dbms_Mysql driver
 */
require_once(PMO_CORE . DS . 'PMO_MyDbms.php');
require_once(PMO_CORE . DS . 'PMO_dbms_mysql.php');

/**
 * this tests the PMO_Dbms_Mysqli connections.
 *
 * This is just a sanity check. Real testing is going to be
 * done with de PMO_MyDbms class.
 *
 * @package			PhpMyObject
 * @subpackage		PMO_Tests
 * @author			Louis Lapointe <laplix@gmail.com>
 * @link				http://pmo.developpez.com/
 * @since			v0.1.16
 * @version			$Revision$
 */
class PMO_Dbms_Mysqli_Connection_Test extends UnitTestCase
{
	/** constructor calls parent contructor. */
	function PMO_Dbms_Mysqli_Connection_Test() {
		$this->UnitTestCase('PMO_Dbms_Mysql Connection Tests (from '.basename(__FILE__).')');
	}

	function setUp() {
		$this->authdb = array(
			'driver' => 'mysqli',
			'pdodriver' => '',
			'host' => 'localhost',
			'user' => 'pmo',
			'pass' => 'pmo',
			'base' => 'test',
			'dsn' => ''
		);
	}

	function tearDown() {
	}

	/***********************
	 * sait pas encore pourquoi mais j'arrive pas à catcher les errors mysql
	 * TODO WORK THIS OUT!!!
	 */
	function test_connect_with_bad_host() {

		$db = new PMO_Dbms_Mysql();
		$this->authdb['host'] = 'qwerty';

		try {
			@$db->connect($this->authdb);
			$this->fail('Should have catched the exception.');
		}
		catch(Exception $e) {
			$this->assertWantedPattern('/Unknown MySQL server host/', $e->getMessage(), $e->getMessage());
		}
	}

	function test_connect_with_bad_user() {

		$db = new PMO_Dbms_mysql();
		$this->authdb['user'] = 'qwerty';
		
		try {
			@$db->connect($this->authdb);
			$this->fail('Should have catched the exception.');
		}
		catch(Exception $e) {
			$this->assertWantedPattern('/Access denied for user \'qwerty\'/', $e->getMessage(), $e->getMessage());
		}
	}

	function test_connect_with_bad_pass() {
		// for the connection tests, we won't use $this->db
		$db = new PMO_Dbms_mysql();
		$this->authdb['pass'] = 'qwerty';

		try {
			@$db->connect($this->authdb);
			$this->fail('Should have catched the exception.');
		}
		catch(Exception $e) {
			$this->assertWantedPattern('/Access denied for user \'pmo\'/', $e->getMessage(), $e->getMessage());
		}
	}

	function test_connect_with_bad_base() {
		// for the connection tests, we won't use $this->db
		$db = new PMO_Dbms_mysql();
		$this->authdb['base'] = 'qwerty';

		try {
			@$db->connect($this->authdb);
			$this->fail('Should have catched the exception.');
		}
		catch(Exception $e) {
			$this->assertWantedPattern('/database \'qwerty\'/', $e->getMessage(), $e->getMessage());
		}
	}

	function test_connect_good_connection() {
		// for the connection tests, we won't use $this->db
		$db = new PMO_Dbms_mysql();

		try {
			$db->connect($this->authdb);
			$this->pass('Connected');
		}
		catch (Exception $e) {
			$this->fail($e->getMessage());
		}
	}

}

/**
 * Tests the PMO_Dbms_Mysqli class
 *
 * This is just a sanity check. Real testing is going to be
 * done with the PMO_MyDbms class.
 *
 * @package			PhpMyObject
 * @subpackage		PMO_Tests
 * @author			Louis Lapointe <laplix@gmail.com>
 * @link				http://pmo.developpez.com/
 * @since			v0.1.16
 * @version			$Revision$
 */
class PMO_Dbms_Mysqli_Test extends UnitTestCase
{
	/** constructor calls parent contructor. */
	function PMO_Dbms_Mysqli_Test() {
		$this->UnitTestCase();
	}

	/**#&+
	 * These functions are called before and after each test.
	 * They are used to initialize the environment si we know
	 * for sure what to expect.
	 */
	/**
	 * Setup the environment before a test.
	 */
	function setUp() {
		$this->authdb = array(
			'driver' => 'mysql',
			'pdodriver' => '',
			'host' => 'localhost',
			'user' => 'pmo',
			'pass' => 'pmo',
			'base' => 'test',
			'dsn' => ''
		);
		$this->setSql();
		$this->db = new PMO_Dbms_Mysql();
		$this->db->connect($this->authdb);
		$this->db->query($this->drop);
		$this->db->query($this->create);

      foreach ($this->inserts as $insert) {
         $sql = 'INSERT INTO `t1` VALUES ' . $insert;
         $this->db->query($sql);
      }
	}

	/**
	 * Reset the environment after a test.
	 */
	function tearDown() {
		$this->db->query($this->drop);
		unset($this->db);
	}
	/**#&-*/

	/**
	 * Setup the SQL needed to initialize the environment.
	 */
	private function setSql() {
		// we need to drop instead of truncate because we need to know
		// the last inserted id in advance.
		$this->drop = 'DROP TABLE IF EXISTS `t1`';
		$this->create = 'CREATE TABLE `t1` ('
					 . '`id` INT(11) NOT NULL AUTO_INCREMENT,'
					 . '`name` VARCHAR(50) NOT NULL DEFAULT \'\','
					 . '`group_id` INT(11) NOT NULL DEFAULT \'0\','
					 . '`description` VARCHAR(255) DEFAULT NULL,'
					 . '`start_date` DATE DEFAULT NULL,'
					 . 'PRIMARY KEY  (`id`)'
					 . ') ENGINE=InnoDB DEFAULT CHARSET=latin1;' ;
      $this->inserts = array(
                   '(1, "one", 1, null, null)'
                  ,'(2, "two", 1, null, null)'
                  ,'(3, "three", 1, "description of three", "2008-02-29")'
                  ,'(4, "four", 10, null, null)'
                  ,'(5, "five", 10, null, null)'
                  ,'(6, "six", 10, null, null)'
                  ,'(7, "seven", 20, null, null)'
                  ,'(8, "eight", 20, null, null)'
                  ,'(9, "nine", 20, null, null)'
               );
	}


	function test_query() {
		$sql = 'select * from t1';
		$this->assertTrue($this->db->query($sql), 'select data that exists');

		try {
			$sql2 = $sql . ' where groups = "40"';
			$this->db->query($sql2);
			$this->fail('should have caught the exception since the column "groups" does not exist');
		}
		catch (Exception $e) {
			$this->assertPattern('/Unknown column \'groups\'/', $e->getMessage(),
			  									'Unknown column groups throws an exception');
		}

		$sql2 = $sql . ' where group_id = 40';
		$this->assertTrue($this->db->query($sql2), 'a select with nonexistent group_id');
 
	}

	function test_fetchArray() {
		$sql = 'select * from t1 where group_id = 1';
		$this->assertTrue($this->db->query($sql), "query [$sql] succeeded");

		$row = $this->db->fetchArray();
		$this->assertEqual(count($row), 5, 'the row does contain 5 columns');
		$this->assertEqual($row['name'], 'one', 'the first row[name] does equal "one"');

		$row = $this->db->fetchArray();
		$this->assertEqual($row['name'], 'two', 'the second row[name] does equal "two"');

		$row = $this->db->fetchArray();
		$this->assertEqual($row['id'], 3, 'the third row[id] does equal 3');
		$this->assertEqual($row['name'], 'three', 'the third row[name] does equal "thre"');
		$this->assertEqual($row['group_id'], 1, 'the third row[group_id] does equal 1');
		$this->assertEqual($row['description'], 'description of three', 'the third row[description] does equal "description of three"');
		$this->assertEqual($row['start_date'], '2008-02-29', 'the third row[start_date] does equal "2008-02-29"');

		$row = $this->db->fetchArray();
		$this->assertFalse($row, 'there are no more rows');
	}

	function test_getTableDesc() {
		$arr = $this->db->getTableDesc('t1');
		$this->assertTrue(is_array($arr), 'getTableDesc(t1) return an array');
		$this->assertEqual(count($arr), 5, 'and returned 5 columns as expected');
		$this->assertEqual($arr[0]['Field'], 'id', 'Field value is "id" as expected');
		$this->assertEqual($arr[0]['Null'], 'NO', 'Null is empty as expected');
		$this->assertEqual($arr[0]['Key'], 'PRI', 'Key contains "PRI" as expected');
		$this->assertEqual($arr[0]['Default'], '', 'Default is empty as expected');
		$this->assertEqual($arr[0]['Extra'], 'auto_increment', 'Extra contains "auto_increment" as expected');
		$this->assertEqual($arr[0]['Perm'], 'rw', 'Perm contains "rw" as expected');
	}

	function test_getLastId() {
		$sql = "insert into `t1` values (0, 'last one', 99, 'a short description', now())";
		$this->db->query($sql);
		$this->assertEqual($this->db->getLastId(), 10, 'New id equals 10 as expected');
	}

	function test_transaction_and_rollback() {
		$insert98 = 'INSERT INTO `t1` VALUES (98, "quatre-vingt dix-huit", 1,null,null)';
		$select98 = 'SELECT * FROM `t1` WHERE id = 98';
		$insert99 = 'INSERT INTO `t1` VALUES (99, "quatre-vingt dix-neuf", 1,null,null)';
		$select99 = 'SELECT * FROM `t1` WHERE id = 99';

		$this->db->beginTransaction();
		$this->db->query($insert98);
		$this->db->commit();
		$this->db->query($select98);
		$res = $this->db->fetchArray();
		$this->assertEqual($res['id'], 98);

		$this->db->beginTransaction();
		$this->db->query($insert99);
		$this->db->rollback();
		$this->db->query($select99);
		$res = $this->db->fetchArray();
		$this->assertEqual($res['id'],NULL);
	}
}

// run the tests if called individually
if (!defined('PMO_TEST_SUITE')) {
	$level = '';
	if (isset($_GET['level']))
		$level = $_GET['level'];

	$test = new TestSuite('DBMB MySQLi Tests');
	$test->add(new PMO_Dbms_Mysqli_Connection_Test);
	$test->add(new PMO_Dbms_Mysqli_Test);
	$test->run(new PMO_HTMLReporter($level));
}

