<?php
/**
 * This file contains the PMO_Dbms_Pdo driver class.
 *
 * 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} 
 * or our mailing list at {@link http://groups.google.com/group/pmo-dev}.
 *
 * 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			PhpMyObject v0.15
 * @version			$Revision$
 * @copyright		Copyright (c) 2008 Louis Lapointe
 * @license			GPLv3 {@link http://www.gnu.org/licenses/gpl}
 * @filesource
 */ 

/**
 * setup the test cases if called individually
 */
if (!defined('PMO_TEST_SUITE')) {
	require_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'config.php');
	require_once(SIMPLETEST.DS.'autorun.php');
	require_once(PMO_TESTS . DS . 'simpletest' . DS . 'PMO_HTMLReporter.php');
}

/**
 * requires the classes to be tested
 */
require_once(PMO_CORE . DS . 'PMO_MyDbms.php');
require_once(PMO_CORE . DS . 'PMO_dbms_pdo.php');
require_once(PMO_CORE . DS . 'PMO_dbms_mysql.php');
require_once(PMO_CORE . DS . 'PMO_dbms_sqlite.php');

/**
 * this tests the PMO_Dbms_Pdo connections.
 *
 * This is just a sanity check. Real testing is going to be
 * done with de PMO_MyDbms class.
 */
class PMO_Dbms_Pdo_Connection_Test extends UnitTestCase
{
	/** constructor calls parent contructor. */
	function PMO_Dbms_Pdo_Connection_Test()
	{
		$this->UnitTestCase();
		$this->sqliteDatabase = dirname(__FILE__).DS.'test.db';
	}

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

	function tearDown() {
		if ($this->authdb['pdodriver'] == 'sqlite') {
			@unlink($this->sqliteDatabase);
		}
	}

	function test_pdo_mysql_connect_with_bad_host()
	{
		$db = new PMO_Dbms_Pdo();
		$this->authdb['pdodriver'] = '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_pdo_mysql_connect_with_bad_user()
	{
		$db = new PMO_Dbms_Pdo();
		$this->authdb['pdodriver'] = 'mysql';
		$this->authdb['user'] = 'qwerty';
		
		try {
			$db->connect($this->authdb);
			$this->fail('Should have catched the exception.');
		}
		catch(PDOException $e) {
			$this->assertWantedPattern('/Access denied for user \'qwerty\'/', $e->getMessage(), $e->getMessage());
		}
	}

	function test_pdo_mysql_connect_with_bad_pass()
	{
		$db = new PMO_Dbms_Pdo();
		$this->authdb['pdodriver'] = 'mysql';
		$this->authdb['pass'] = 'qwerty';

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

	function test_pdo_mysql_connect_with_bad_base()
	{
		$db = new PMO_Dbms_Pdo();
		$this->authdb['pdodriver'] = '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_pdo_mysql_connect_good_connection()
	{
		$db = new PMO_Dbms_Pdo();
		$this->authdb['pdodriver'] = 'mysql';

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

}


/**
 * This tests the PMO_dbms_pdo class.
 *
 * This is just a sanity check. Real testing is going to be
 * done with de PMO_MyDbms class.
 */
class PMO_Dbms_Pdo_Test extends UnitTestCase 
{
	/** constructor calls parent contructor. */
	function PMO_Dbms_Pdo_Test()
	{
		$this->UnitTestCase();
		$this->sqliteDatabase = dirname(__FILE__).'/test.db';
		$this->setSql();
	}

	/**
	 * setup is called before each test is performed
	 */
	function setUp()
	{
		$this->authdb = array(
			'driver' => 'pdo',
			'pdodriver' => 'mysql',
			'host' => 'localhost',
			'user' => 'pmo',
			'pass' => 'pmo',
			'base' => 'test',
			'dsn' => 'sqlite:',$this->sqliteDatabase
		);

		$this->db = new PMO_Dbms_Pdo();
		$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);
		}
	}

	/**
	 * tearDown is called after each test has been performed
	 */
	function tearDown()
	{
		$this->db->query($this->drop);
		unset($this->db);
	}

	// helpers
	function setSql()
	{
		// we need to drop instead of truncate because we need to know
		// the last inserted id.
		$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 four", "2008-02-29")'
						,'(4, "four", 10, null, null)'
						,'(5, "five", 10, null, null)'
						,'(6, "six", 10, null, null)'
						,'(7, "seven", 10, 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->assertWantedPattern('/Unknown column \'groups\'/', $e->getMessage()); //, $e->getMessage());
		}

		$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 "three"');
		$this->assertEqual($row['group_id'], 1, 'the third row[group_id] does equal 1');
		$this->assertEqual($row['description'], 'description of four', 'the third row[description] does equal "description of four"');
		$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 equals NO 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_commit() {
		$insert98 = 'INSERT INTO `t1` VALUES (98, "quatre-vingt dix-huit", 1,null,null)';
		$select98 = 'SELECT * FROM `t1` WHERE id = 98';

		$this->db->beginTransaction();
		$this->db->query($insert98);
		$this->db->commit();
		$this->db->query($select98);
		$res = $this->db->fetchArray();
		$this->assertEqual($res['id'], 98);
	}
	
	function test_transaction_rollback() {
		$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($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($_COOKIE['testLevel'])) {
		$level = $_COOKIE['testLevel'];
	}
	elseif (isset($_GET['level'])) {
		$level = $_GET['level'];
		setcookie('testLevel', $level, time()+60*60*24*30);
	}

	$test = new TestSuite('PMO_Dbms_Pdo Tests');
	$test->add(new PMO_Dbms_Pdo_Connection_Test);
	$test->add(new PMO_Dbms_Pdo_Test);
	$test->run(new PMO_HTMLReporter($level));
}

