Merge branch 'develop' of git://github.com/EllisLab/CodeIgniter into email
diff --git a/application/errors/error_php.php b/application/errors/error_php.php
index 3855720..b76dc8a 100644
--- a/application/errors/error_php.php
+++ b/application/errors/error_php.php
@@ -40,12 +40,15 @@
 	<p>Backtrace: </p>
 	<?php foreach(debug_backtrace() as $error): ?>
 
-		<?php if(isset($error['file']) &&  ! stristr($error['file'], SYSDIR)): ?>
+		<?php if(isset($error['file']) &&
+		         strpos($error['file'], realpath(BASEPATH)) !== 0): ?>
+
 			<p style="margin-left:10px">
 			File: <?php echo $error['file'] ?><br />
 			Line: <?php echo $error['line'] ?><br />
 			Function: <?php echo $error['function'] ?>
 			</p>
+
 		<?php endif ?>
 
 	<?php endforeach ?></p>
diff --git a/system/database/drivers/pdo/pdo_result.php b/system/database/drivers/pdo/pdo_result.php
index 19aee1d..0b8937c 100644
--- a/system/database/drivers/pdo/pdo_result.php
+++ b/system/database/drivers/pdo/pdo_result.php
@@ -84,19 +84,14 @@
 		// Define the output
 		$output = array('assoc', 'object');
 
+		// Initial value
+		$this->result_assoc = array() and $this->result_object = array();
+
 		// Fetch the result
-		foreach ($output as $type)
+		while ($row = $this->_fetch_assoc())
 		{
-			// Define the method and handler
-			$res_method  = '_fetch_'.$type;
-			$res_handler = 'result_'.$type;
-
-			$this->$res_handler = array();
-
-			while ($row = $this->$res_method())
-			{
-				$this->{$res_handler}[] = $row;
-			}
+			$this->result_assoc[] = $row;
+			$this->result_object[] = (object) $row;
 		}
 
 		// Save this as buffer and marked the fetch flag
@@ -249,7 +244,7 @@
 	 */
 	protected function _fetch_object()
 	{
-		return $this->result_id->fetchObject();
+		return $this->result_id->fetch(PDO::FETCH_OBJ);
 	}
 
 }
diff --git a/system/database/drivers/postgre/postgre_driver.php b/system/database/drivers/postgre/postgre_driver.php
index 84bf768..17bd37b 100644
--- a/system/database/drivers/postgre/postgre_driver.php
+++ b/system/database/drivers/postgre/postgre_driver.php
@@ -311,6 +311,27 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * "Smart" Escape String
+	 *
+	 * Escapes data based on type
+	 * Sets boolean and null types
+	 *
+	 * @param	string
+	 * @return	mixed
+	 */
+	public function escape($str)
+	{
+		if (is_bool($str))
+		{
+			return ($str) ? 'TRUE' : 'FALSE';
+		}
+
+		return parent::escape($str);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Affected Rows
 	 *
 	 * @return	int
@@ -558,6 +579,78 @@
 	// --------------------------------------------------------------------
 
 	/**
+	 * Where
+	 *
+	 * Called by where() or or_where()
+	 *
+	 * @param	mixed
+	 * @param	mixed
+	 * @param	string
+	 * @return	object
+	 *
+	 */
+	protected function _where($key, $value = NULL, $type = 'AND ', $escape = NULL)
+	{
+		$type = $this->_group_get_type($type);
+
+		if ( ! is_array($key))
+		{
+			$key = array($key => $value);
+		}
+
+		// If the escape value was not set will will base it on the global setting
+		if ( ! is_bool($escape))
+		{
+			$escape = $this->_protect_identifiers;
+		}
+
+		foreach ($key as $k => $v)
+		{
+			$prefix = (count($this->qb_where) === 0 && count($this->qb_cache_where) === 0) ? '' : $type;
+
+			if (is_null($v) && ! $this->_has_operator($k))
+			{
+				// value appears not to have been set, assign the test to IS NULL
+				$k .= ' IS NULL';
+			}
+
+			if ( ! is_null($v))
+			{
+				if ($escape === TRUE)
+				{
+					$k = $this->protect_identifiers($k, FALSE, $escape);
+					$v = ' '.$this->escape($v);
+				}
+				elseif (is_bool($v))
+				{
+					$v = ($v ? ' TRUE' : ' FALSE');
+				}
+
+				if ( ! $this->_has_operator($k))
+				{
+					$k .= ' = ';
+				}
+			}
+			else
+			{
+				$k = $this->protect_identifiers($k, FALSE, $escape);
+			}
+
+			$this->qb_where[] = $prefix.$k.$v;
+			if ($this->qb_caching === TRUE)
+			{
+				$this->qb_cache_where[] = $prefix.$k.$v;
+				$this->qb_cache_exists[] = 'where';
+			}
+
+		}
+
+		return $this;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
 	 * Close DB Connection
 	 *
 	 * @param	resource
@@ -571,4 +664,4 @@
 }
 
 /* End of file postgre_driver.php */
-/* Location: ./system/database/drivers/postgre/postgre_driver.php */
+/* Location: ./system/database/drivers/postgre/postgre_driver.php */
\ No newline at end of file
diff --git a/tests/README.md b/tests/README.md
index 6d83c34..c8fc608 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -1,12 +1,6 @@
 # CodeIgniter Unit Tests #
 
-Status : [![Build Status](https://secure.travis-ci.org/EllisLab/CodeIgniter.png?branch=feature/unit-tests)](http://travis-ci.org/EllisLab/CodeIgniter)
-
-*Do not merge to default until these issues have been addressed*
-
-- Clean up naming conventions
-- Figure out config stuff
-- Figure out database testing
+Status : [![Build Status](https://secure.travis-ci.org/EllisLab/CodeIgniter.png?branch=develop)](http://travis-ci.org/EllisLab/CodeIgniter)
 
 ### Introduction:
 
diff --git a/tests/codeigniter/Setup_test.php b/tests/codeigniter/Setup_test.php
index 550245f..b48e32b 100644
--- a/tests/codeigniter/Setup_test.php
+++ b/tests/codeigniter/Setup_test.php
@@ -2,12 +2,12 @@
 
 class Setup_test extends PHPUnit_Framework_TestCase {
 	
-	function test_nonsense()
+	function test_bootstrap_constants()
 	{
-		$this->markTestIncomplete('not implemented');
-		// ensure that our bootstrapped test environment
-		// is a good representation of an isolated CI install
-		//die('here');
+		$this->assertTrue(defined('PROJECT_BASE'));
+		$this->assertTrue(defined('BASEPATH'));
+		$this->assertTrue(defined('APPPATH'));
+		$this->assertTrue(defined('VIEWPATH'));
 	}
 	
 }
\ No newline at end of file
diff --git a/tests/codeigniter/core/Benchmark_test.php b/tests/codeigniter/core/Benchmark_test.php
new file mode 100644
index 0000000..109b388
--- /dev/null
+++ b/tests/codeigniter/core/Benchmark_test.php
@@ -0,0 +1,42 @@
+<?php
+
+class Benchmark_test extends CI_TestCase {
+	
+	public function set_up()
+	{
+		$this->benchmark = new Mock_Core_Benchmark();
+	}
+	
+	// --------------------------------------------------------------------
+	
+	public function test_mark()
+	{
+		$this->assertEmpty($this->benchmark->marker);
+
+		$this->benchmark->mark('code_start');
+
+		$this->assertEquals(1, count($this->benchmark->marker));
+		$this->assertArrayHasKey('code_start', $this->benchmark->marker);
+	}
+	
+	// --------------------------------------------------------------------
+
+	public function test_elapsed_time()
+	{
+		$this->assertEquals('{elapsed_time}', $this->benchmark->elapsed_time());
+		$this->assertEmpty($this->benchmark->elapsed_time('undefined_point'));
+
+		$this->benchmark->mark('code_start');
+		sleep(1);
+		$this->benchmark->mark('code_end');
+		
+		$this->assertEquals('1.0', $this->benchmark->elapsed_time('code_start', 'code_end', 1));
+	}
+
+	// --------------------------------------------------------------------
+
+	public function test_memory_usage()
+	{
+		$this->assertEquals('{memory_usage}', $this->benchmark->memory_usage());
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Input_test.php b/tests/codeigniter/core/Input_test.php
new file mode 100644
index 0000000..fd0576e
--- /dev/null
+++ b/tests/codeigniter/core/Input_test.php
@@ -0,0 +1,144 @@
+<?php
+
+class Input_test extends CI_TestCase {
+	
+	public function set_up()
+	{
+		// Set server variable to GET as default, since this will leave unset in STDIN env
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		// Set config for Input class
+		$this->ci_set_config('allow_get_array',	TRUE);
+		$this->ci_set_config('global_xss_filtering', FALSE);
+		$this->ci_set_config('csrf_protection', FALSE);
+
+		$security = new Mock_Core_Security();
+		$utf8 = new Mock_Core_Utf8();
+
+		$this->input = new Mock_Core_Input($security, $utf8);
+	}
+	
+	// --------------------------------------------------------------------
+	
+	public function test_get_not_exists()
+	{
+		$this->assertEmpty($this->input->get());
+		$this->assertEmpty($this->input->get('foo'));
+
+		$this->assertTrue( ! $this->input->get());
+		$this->assertTrue( ! $this->input->get('foo'));
+
+		$this->assertTrue($this->input->get() == FALSE);
+		$this->assertTrue($this->input->get('foo') == FALSE);
+
+		$this->assertTrue($this->input->get() === FALSE);
+		$this->assertTrue($this->input->get('foo') === FALSE);
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_get_exist()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['foo'] = 'bar';
+
+		$this->assertArrayHasKey('foo', $this->input->get());
+		$this->assertEquals('bar', $this->input->get('foo'));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_get_exist_with_xss_clean()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+		$_GET['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$this->assertArrayHasKey('harm', $this->input->get());
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->get('harm'));
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $this->input->get('harm', TRUE));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_post_not_exists()
+	{
+		$this->assertEmpty($this->input->post());
+		$this->assertEmpty($this->input->post('foo'));
+
+		$this->assertTrue( ! $this->input->post());
+		$this->assertTrue( ! $this->input->post('foo'));
+
+		$this->assertTrue($this->input->post() == FALSE);
+		$this->assertTrue($this->input->post('foo') == FALSE);
+
+		$this->assertTrue($this->input->post() === FALSE);
+		$this->assertTrue($this->input->post('foo') === FALSE);
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_post_exist()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['foo'] = 'bar';
+
+		$this->assertArrayHasKey('foo', $this->input->post());
+		$this->assertEquals('bar', $this->input->post('foo'));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_post_exist_with_xss_clean()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['harm'] = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$this->assertArrayHasKey('harm', $this->input->post());
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $this->input->post('harm'));
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $this->input->post('harm', TRUE));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_get_post()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST['foo'] = 'bar';
+
+		$this->assertEquals('bar', $this->input->get_post('foo'));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_cookie()
+	{
+		$_COOKIE['foo'] = 'bar';
+
+		$this->assertEquals('bar', $this->input->cookie('foo'));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_server()
+	{
+		$this->assertEquals('GET', $this->input->server('REQUEST_METHOD'));
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_fetch_from_array()
+	{
+		$data = array(
+			'foo' => 'bar',
+			'harm' => 'Hello, i try to <script>alert(\'Hack\');</script> your site',
+		);
+
+		$foo = $this->input->fetch_from_array($data, 'foo');
+		$harm = $this->input->fetch_from_array($data, 'harm');
+		$harmless = $this->input->fetch_from_array($data, 'harm', TRUE);
+
+		$this->assertEquals('bar', $foo);
+		$this->assertEquals("Hello, i try to <script>alert('Hack');</script> your site", $harm);
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/core/Security_test.php b/tests/codeigniter/core/Security_test.php
new file mode 100644
index 0000000..1796ba7
--- /dev/null
+++ b/tests/codeigniter/core/Security_test.php
@@ -0,0 +1,73 @@
+<?php
+
+class Security_test extends CI_TestCase {
+	
+	public function set_up()
+	{
+		// Set cookie for security test
+		$_COOKIE['ci_csrf_cookie'] = md5(uniqid(rand(), TRUE));
+
+		// Set config for Security class
+		$this->ci_set_config('csrf_protection', TRUE);
+		$this->ci_set_config('csrf_token_name', 'ci_csrf_token');
+		$this->ci_set_config('csrf_cookie_name', 'ci_csrf_cookie');
+
+		$this->security = new Mock_Core_Security();
+	}
+	
+	// --------------------------------------------------------------------
+	
+	public function test_csrf_verify()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		$this->assertInstanceOf('CI_Security', $this->security->csrf_verify());
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_csrf_verify_invalid()
+	{
+		// Without issuing $_POST[csrf_token_name], this request will triggering CSRF error
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+
+		$this->setExpectedException('RuntimeException', 'CI Error: The action you have requested is not allowed');
+
+		$this->security->csrf_verify();
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_csrf_verify_valid()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'POST';
+		$_POST[$this->security->csrf_token_name] = $this->security->csrf_hash;
+
+		$this->assertInstanceOf('CI_Security', $this->security->csrf_verify());
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_get_csrf_hash()
+	{
+		$this->assertEquals($this->security->csrf_hash, $this->security->get_csrf_hash());
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_get_csrf_token_name()
+	{
+		$this->assertEquals('ci_csrf_token', $this->security->get_csrf_token_name());
+	}
+
+	// --------------------------------------------------------------------
+	
+	public function test_xss_clean()
+	{
+		$harm_string = "Hello, i try to <script>alert('Hack');</script> your site";
+
+		$harmless_string = $this->security->xss_clean($harm_string);
+
+		$this->assertEquals("Hello, i try to [removed]alert&#40;'Hack'&#41;;[removed] your site", $harmless_string);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/count_test.php b/tests/codeigniter/database/query_builder/count_test.php
new file mode 100644
index 0000000..5e69169
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/count_test.php
@@ -0,0 +1,44 @@
+<?php
+
+class Count_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_count_all()
+	{
+		$job_count = $this->db->count_all('job');
+		
+		// Check the result
+		$this->assertEquals(4, $job_count);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_count_all_results()
+	{
+		$job_count = $this->db->like('name', 'ian')
+		                      ->count_all_results('job');
+		
+		// Check the result
+		$this->assertEquals(2, $job_count);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/delete_test.php b/tests/codeigniter/database/query_builder/delete_test.php
new file mode 100644
index 0000000..84ea761
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/delete_test.php
@@ -0,0 +1,72 @@
+<?php
+
+class Delete_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_delete()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 1)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Developer', $job1->name);
+
+		// Do the delete
+		$this->db->delete('job', array('id' => 1));
+
+		// Check the record
+		$job1 = $this->db->where('id', 1)
+							->get('job');
+
+		$this->assertEmpty($job1->result_array());
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_delete_several_tables()
+	{
+		// Check initial record
+		$user4 = $this->db->where('id', 4)
+							->get('user')
+							->row();
+
+		$job4 = $this->db->where('id', 4)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Musician', $job4->name);
+		$this->assertEquals('Chris Martin', $user4->name);
+
+		// Do the delete
+		$this->db->delete(array('job', 'user'), array('id' => 4));
+
+		// Check the record
+		$job4 = $this->db->where('id', 4)->get('job');
+		$user4 = $this->db->where('id', 4)->get('user');
+
+		$this->assertEmpty($job4->result_array());
+		$this->assertEmpty($user4->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/distinct_test.php b/tests/codeigniter/database/query_builder/distinct_test.php
new file mode 100644
index 0000000..925eadb
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/distinct_test.php
@@ -0,0 +1,34 @@
+<?php
+
+class Distinct_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_distinct()
+	{
+		$users = $this->db->select('country')
+							  ->distinct()
+		                      ->get('user')
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(3, count($users));
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/empty_test.php b/tests/codeigniter/database/query_builder/empty_test.php
new file mode 100644
index 0000000..d1f5628
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/empty_test.php
@@ -0,0 +1,39 @@
+<?php
+
+class Empty_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_empty_table()
+	{
+		// Check initial record
+		$jobs = $this->db->get('job')->result_array();
+
+		$this->assertEquals(4, count($jobs));
+
+		// Do the empty
+		$this->db->empty_table('job');
+
+		// Check the record
+		$jobs = $this->db->get('job');
+
+		$this->assertEmpty($jobs->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/from_test.php b/tests/codeigniter/database/query_builder/from_test.php
new file mode 100644
index 0000000..95ae4df
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/from_test.php
@@ -0,0 +1,51 @@
+<?php
+
+class From_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_from_simple()
+	{
+		$jobs = $this->db->from('job')
+		                      ->get()
+		                      ->result_array();
+		
+		// Check items
+		$this->assertEquals(4, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_from_with_where()
+	{
+		$job1 = $this->db->from('job')
+							->where('id', 1)
+		                    ->get()
+		                    ->row();
+		
+		// Check the result
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+		$this->assertEquals('Awesome job, but sometimes makes you bored', $job1->description);
+	}
+	
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/group_test.php b/tests/codeigniter/database/query_builder/group_test.php
new file mode 100644
index 0000000..7d8abc3
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/group_test.php
@@ -0,0 +1,53 @@
+<?php
+
+class Group_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_group_by()
+	{
+		$jobs = $this->db->select('name')
+							  ->from('job')
+							  ->group_by('name')
+		                      ->get()
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(4, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_having_by()
+	{
+		$jobs = $this->db->select('name')
+							  ->from('job')
+							  ->group_by('name')
+							  ->having('SUM(id) > 2')
+		                      ->get()
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(2, count($jobs));
+	}
+	
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/insert_test.php b/tests/codeigniter/database/query_builder/insert_test.php
index 53ce23c..8ba60e2 100644
--- a/tests/codeigniter/database/query_builder/insert_test.php
+++ b/tests/codeigniter/database/query_builder/insert_test.php
@@ -30,11 +30,10 @@
 		// Do normal insert
 		$this->assertTrue($this->db->insert('job', $job_data));
 
-		$jobs = $this->db->get('job')->result_array();
-		$job1 = $jobs[0];
+		$job1 = $this->db->get('job')->row();
 
 		// Check the result
-		$this->assertEquals('Grocery Sales', $job1['name']);
+		$this->assertEquals('Grocery Sales', $job1->name);
 
 	}
 
diff --git a/tests/codeigniter/database/query_builder/join_test.php b/tests/codeigniter/database/query_builder/join_test.php
new file mode 100644
index 0000000..e05329d
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/join_test.php
@@ -0,0 +1,38 @@
+<?php
+
+class Join_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_join_simple()
+	{
+		$job_user = $this->db->select('job.id as job_id, job.name as job_name, user.id as user_id, user.name as user_name')
+							->from('job')
+							->join('user', 'user.id = job.id')
+							->get()
+							->result_array();
+
+		// Check the result
+		$this->assertEquals('1', $job_user[0]['job_id']);
+		$this->assertEquals('1', $job_user[0]['user_id']);
+		$this->assertEquals('Derek Jones', $job_user[0]['user_name']);
+		$this->assertEquals('Developer', $job_user[0]['job_name']);
+	}
+	
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/like_test.php b/tests/codeigniter/database/query_builder/like_test.php
new file mode 100644
index 0000000..df98c71
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/like_test.php
@@ -0,0 +1,90 @@
+<?php
+
+class Like_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_like()
+	{
+		$job1 = $this->db->like('name', 'veloper')
+							->get('job')
+							->row();
+
+		// Check the result
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_or_like()
+	{
+		$jobs = $this->db->like('name', 'ian')
+							->or_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Politician', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_not_like()
+	{
+		$jobs = $this->db->not_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_or_not_like()
+	{
+		$jobs = $this->db->like('name', 'an')
+							->or_not_like('name', 'veloper')
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+	
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/limit_test.php b/tests/codeigniter/database/query_builder/limit_test.php
new file mode 100644
index 0000000..704f3b6
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/limit_test.php
@@ -0,0 +1,49 @@
+<?php
+
+class Limit_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_limit()
+	{
+		$jobs = $this->db->limit(2)
+		                      ->get('job')
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(2, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_limit_and_offset()
+	{
+		$jobs = $this->db->limit(2, 2)
+		                      ->get('job')
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Accountant', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/order_test.php b/tests/codeigniter/database/query_builder/order_test.php
new file mode 100644
index 0000000..01aa1c2
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/order_test.php
@@ -0,0 +1,55 @@
+<?php
+
+class Order_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_order_ascending()
+	{
+		$jobs = $this->db->order_by('name', 'asc')
+		                      ->get('job')
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(4, count($jobs));
+		$this->assertEquals('Accountant', $jobs[0]['name']);
+		$this->assertEquals('Developer', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+		$this->assertEquals('Politician', $jobs[3]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_order_descending()
+	{
+		$jobs = $this->db->order_by('name', 'desc')
+		                      ->get('job')
+		                      ->result_array();
+		
+		// Check the result
+		$this->assertEquals(4, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+		$this->assertEquals('Developer', $jobs[2]['name']);
+		$this->assertEquals('Accountant', $jobs[3]['name']);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/select_test.php b/tests/codeigniter/database/query_builder/select_test.php
index dbf432a..0d299ed 100644
--- a/tests/codeigniter/database/query_builder/select_test.php
+++ b/tests/codeigniter/database/query_builder/select_test.php
@@ -41,10 +41,10 @@
 	{
 		$job_min = $this->db->select_min('id')
 		                    ->get('job')
-		                    ->result_array();
+		                    ->row();
 		
 		// Minimum id was 1
-		$this->assertEquals('1', $job_min[0]['id']);
+		$this->assertEquals('1', $job_min->id);
 	}
 
 	// ------------------------------------------------------------------------
@@ -56,10 +56,10 @@
 	{
 		$job_max = $this->db->select_max('id')
 		                    ->get('job')
-		                    ->result_array();
+		                    ->row();
 		
 		// Maximum id was 4
-		$this->assertEquals('4', $job_max[0]['id']);
+		$this->assertEquals('4', $job_max->id);
 	}
 
 	// ------------------------------------------------------------------------
@@ -71,10 +71,10 @@
 	{
 		$job_avg = $this->db->select_avg('id')
 		                    ->get('job')
-		                    ->result_array();
+		                    ->row();
 		
 		// Average should be 2.5
-		$this->assertEquals('2.5', $job_avg[0]['id']);
+		$this->assertEquals('2.5', $job_avg->id);
 	}
 
 	// ------------------------------------------------------------------------
@@ -86,10 +86,10 @@
 	{
 		$job_sum = $this->db->select_sum('id')
 		                    ->get('job')
-		                    ->result_array();
+		                    ->row();
 		
 		// Sum of ids should be 10
-		$this->assertEquals('10', $job_sum[0]['id']);
+		$this->assertEquals('10', $job_sum->id);
 	}
 	
 }
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/truncate_test.php b/tests/codeigniter/database/query_builder/truncate_test.php
new file mode 100644
index 0000000..2a9c8a9
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/truncate_test.php
@@ -0,0 +1,61 @@
+<?php
+
+class Truncate_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_truncate()
+	{
+		// Check initial record
+		$jobs = $this->db->get('job')->result_array();
+
+		$this->assertEquals(4, count($jobs));
+
+		// Do the empty
+		$this->db->truncate('job');
+
+		// Check the record
+		$jobs = $this->db->get('job');
+
+		$this->assertEmpty($jobs->result_array());
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_truncate_with_from()
+	{
+		// Check initial record
+		$users = $this->db->get('user')->result_array();
+
+		$this->assertEquals(4, count($users));
+
+		// Do the empty
+		$this->db->from('user')
+					->truncate();
+
+		// Check the record
+		$users = $this->db->get('user');
+
+		$this->assertEmpty($users->result_array());
+	}
+
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/update_test.php b/tests/codeigniter/database/query_builder/update_test.php
new file mode 100644
index 0000000..f5bbffd
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/update_test.php
@@ -0,0 +1,71 @@
+<?php
+
+class Update_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_update()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 1)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Developer', $job1->name);
+
+		// Do the update
+		$job_data = array('name' => 'Programmer');
+
+		$this->db->where('id', 1)
+						->update('job', $job_data);
+
+		// Check updated record
+		$job1 = $this->db->where('id', 1)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Programmer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_update_with_set()
+	{
+		// Check initial record
+		$job1 = $this->db->where('id', 4)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Musician', $job1->name);
+
+		// Do the update
+		$this->db->set('name', 'Vocalist');
+		$this->db->update('job', NULL, 'id = 4');
+
+		// Check updated record
+		$job1 = $this->db->where('id', 4)
+							->get('job')
+							->row();
+
+		$this->assertEquals('Vocalist', $job1->name);
+	}
+}
\ No newline at end of file
diff --git a/tests/codeigniter/database/query_builder/where_test.php b/tests/codeigniter/database/query_builder/where_test.php
new file mode 100644
index 0000000..607eaa0
--- /dev/null
+++ b/tests/codeigniter/database/query_builder/where_test.php
@@ -0,0 +1,144 @@
+<?php
+
+class Where_test extends CI_TestCase {
+
+	/**
+	 * @var object Database/Query Builder holder
+	 */
+	protected $db;
+
+	public function set_up()
+	{
+		$this->db = Mock_Database_Schema_Skeleton::init(DB_DRIVER);
+
+		Mock_Database_Schema_Skeleton::create_tables();
+		Mock_Database_Schema_Skeleton::create_data();
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_simple_key_value()
+	{
+		$job1 = $this->db->where('id', 1)
+							->get('job')
+							->row();
+
+		// Check the result
+		$this->assertEquals('1', $job1->id);
+		$this->assertEquals('Developer', $job1->name);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_custom_key_value()
+	{
+		$jobs = $this->db->where('id !=', 1)
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_associative_array()
+	{
+		$where = array('id >' => 2, 'name !=' => 'Accountant');
+		$jobs = $this->db->where($where)
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(1, count($jobs));
+
+		// Should be Musician
+		$job = current($jobs);
+
+		$this->assertEquals('Musician', $job['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_custom_string()
+	{
+		$where = "id > 2 AND name != 'Accountant'";
+		$jobs = $this->db->where($where)
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(1, count($jobs));
+
+		// Should be Musician
+		$job = current($jobs);
+
+		$this->assertEquals('Musician', $job['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_or()
+	{
+		$jobs = $this->db->where('name !=', 'Accountant')
+							->or_where('id >', 3)
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(3, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Politician', $jobs[1]['name']);
+		$this->assertEquals('Musician', $jobs[2]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_in()
+	{
+		$jobs = $this->db->where_in('name', array('Politician', 'Accountant'))
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Politician', $jobs[0]['name']);
+		$this->assertEquals('Accountant', $jobs[1]['name']);
+	}
+
+	// ------------------------------------------------------------------------
+
+	/**
+	 * @see ./mocks/schema/skeleton.php
+	 */
+	public function test_where_not_in()
+	{
+		$jobs = $this->db->where_not_in('name', array('Politician', 'Accountant'))
+							->get('job')
+							->result_array();
+
+		// Check the result
+		$this->assertEquals(2, count($jobs));
+		$this->assertEquals('Developer', $jobs[0]['name']);
+		$this->assertEquals('Musician', $jobs[1]['name']);
+	}
+	
+}
\ No newline at end of file
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index f1bdb5d..92c9bea 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -6,7 +6,6 @@
 //
 // Prototype :
 //
-// include_once('Mock_Core_Loader') 					// Will load ./mocks/core/loader.php
 // $mock_table = new Mock_Libraries_Table(); 			// Will load ./mocks/libraries/table.php
 // $mock_database_driver = new Mock_Database_Driver();	// Will load ./mocks/database/driver.php 
 // and so on...
diff --git a/tests/mocks/core/benchmark.php b/tests/mocks/core/benchmark.php
new file mode 100644
index 0000000..d92be21
--- /dev/null
+++ b/tests/mocks/core/benchmark.php
@@ -0,0 +1,3 @@
+<?php
+
+class Mock_Core_Benchmark extends CI_Benchmark {}
\ No newline at end of file
diff --git a/tests/mocks/core/input.php b/tests/mocks/core/input.php
new file mode 100644
index 0000000..8a337d2
--- /dev/null
+++ b/tests/mocks/core/input.php
@@ -0,0 +1,31 @@
+<?php
+
+class Mock_Core_Input extends CI_Input {
+	
+	/**
+	 * Since we use GLOBAL to fetch Security and Utf8 classes, 
+	 * we need to use inversion of control to mock up 
+	 * the same process within CI_Input class constructor.
+	 *
+	 * @covers CI_Input::__construct()
+	 */
+	public function __construct($security, $utf8)
+	{
+		$this->_allow_get_array	= (config_item('allow_get_array') === TRUE);
+		$this->_enable_xss	= (config_item('global_xss_filtering') === TRUE);
+		$this->_enable_csrf	= (config_item('csrf_protection') === TRUE);
+
+		// Assign Security and Utf8 classes
+		$this->security = $security;
+		$this->uni = $utf8;
+
+		// Sanitize global arrays
+		$this->_sanitize_globals();
+	}
+
+	public function fetch_from_array($array, $index = '', $xss_clean = FALSE)
+	{
+		return parent::_fetch_from_array($array, $index, $xss_clean);
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/security.php b/tests/mocks/core/security.php
new file mode 100644
index 0000000..d7ea0e6
--- /dev/null
+++ b/tests/mocks/core/security.php
@@ -0,0 +1,30 @@
+<?php
+
+class Mock_Core_Security extends CI_Security {
+	
+	public function csrf_set_cookie()
+	{
+		// We cannot set cookie in CLI mode, so for csrf test, who rely on $_COOKIE,
+		// we superseded set_cookie with directly set the cookie variable,
+		// @see : ./tests/codeigniter/core/Security_test.php, line 8
+		return $this;
+	}
+
+	// Overide inaccesible protected properties
+	public function __get($property)
+	{
+		return isset($this->{'_'.$property}) ? $this->{'_'.$property} : NULL;
+	}
+
+	// Overide inaccesible protected method
+	public function __call($method, $params)
+	{
+		if (is_callable(array($this, '_'.$method)))
+		{
+			return call_user_func_array(array($this, '_'.$method), $params);
+		}
+
+		throw new BadMethodCallException('Method '.$method.' was not found');
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/core/utf8.php b/tests/mocks/core/utf8.php
new file mode 100644
index 0000000..b77d717
--- /dev/null
+++ b/tests/mocks/core/utf8.php
@@ -0,0 +1,27 @@
+<?php
+
+class Mock_Core_Utf8 extends CI_Utf8 {
+	
+	/**
+	 * We need to define several constants as 
+	 * the same process within CI_Utf8 class constructor.
+	 *
+	 * @covers CI_Utf8::__construct()
+	 */
+	public function __construct()
+	{
+		defined('UTF8_ENABLED') or define('UTF8_ENABLED', TRUE);
+
+		if (extension_loaded('mbstring'))
+		{
+			defined('MB_ENABLED') or define('MB_ENABLED', TRUE);
+			mb_internal_encoding('UTF-8');
+		}
+		else
+		{
+			defined('MB_ENABLED') or define('MB_ENABLED', FALSE);
+		}
+		
+	}
+
+}
\ No newline at end of file
diff --git a/tests/mocks/database/ci_test.sqlite b/tests/mocks/database/ci_test.sqlite
index 86d868a..23a3de2 100755
--- a/tests/mocks/database/ci_test.sqlite
+++ b/tests/mocks/database/ci_test.sqlite
Binary files differ
diff --git a/tests/mocks/database/schema/skeleton.php b/tests/mocks/database/schema/skeleton.php
index a3d5bac..671336c 100644
--- a/tests/mocks/database/schema/skeleton.php
+++ b/tests/mocks/database/schema/skeleton.php
@@ -50,6 +50,28 @@
 	 */
 	public static function create_tables()
 	{
+		// User Table
+		static::$forge->add_field(array(
+			'id' => array(
+				'type' => 'INTEGER',
+				'constraint' => 3,
+			),
+			'name' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40,
+			),
+			'email' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 100,
+			),
+			'country' => array(
+				'type' => 'VARCHAR',
+				'constraint' => 40,
+			),
+		));
+		static::$forge->add_key('id', TRUE);
+		static::$forge->create_table('user', (strpos(static::$driver, 'pgsql') === FALSE));
+
 		// Job Table
 		static::$forge->add_field(array(
 			'id' => array(
@@ -77,6 +99,12 @@
 	{
 		// Job Data
 		$data = array(
+			'user' => array(
+				array('id' => 1, 'name' => 'Derek Jones', 'email' => 'derek@world.com', 'country' => 'US'),
+				array('id' => 2, 'name' => 'Ahmadinejad', 'email' => 'ahmadinejad@world.com', 'country' => 'Iran'),
+				array('id' => 3, 'name' => 'Richard A Causey', 'email' => 'richard@world.com', 'country' => 'US'),
+				array('id' => 4, 'name' => 'Chris Martin', 'email' => 'chris@world.com', 'country' => 'UK'),
+			),
 			'job' => array(
 				array('id' => 1, 'name' => 'Developer', 'description' => 'Awesome job, but sometimes makes you bored'), 
 				array('id' => 2, 'name' => 'Politician', 'description' => 'This is not really a job'),
diff --git a/tests/mocks/libraries/table.php b/tests/mocks/libraries/table.php
index 1a6ff8d..97fbb30 100644
--- a/tests/mocks/libraries/table.php
+++ b/tests/mocks/libraries/table.php
@@ -2,7 +2,7 @@
 
 class Mock_Libraries_Table extends CI_Table {
 	
-	// Overide inaccesible private or protected method
+	// Overide inaccesible protected method
 	public function __call($method, $params)
 	{
 		if (is_callable(array($this, '_'.$method)))
diff --git a/tests/travis/mysql.phpunit.xml b/tests/travis/mysql.phpunit.xml
index e9556f7..1792ae3 100644
--- a/tests/travis/mysql.phpunit.xml
+++ b/tests/travis/mysql.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../codeigniter/core</directory>
-			<directory suffix="test.php">../codeigniter/helpers</directory>
-			<directory suffix="test.php">../codeigniter/libraries</directory>
-			<directory suffix="test.php">../codeigniter/database</directory>
+			<directory suffix="test.php">../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/mysql.phpunit.xml b/tests/travis/pdo/mysql.phpunit.xml
index 69eece2..602030d 100644
--- a/tests/travis/pdo/mysql.phpunit.xml
+++ b/tests/travis/pdo/mysql.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../../codeigniter/core</directory>
-			<directory suffix="test.php">../../codeigniter/helpers</directory>
-			<directory suffix="test.php">../../codeigniter/libraries</directory>
-			<directory suffix="test.php">../../codeigniter/database</directory>
+			<directory suffix="test.php">../../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/pgsql.phpunit.xml b/tests/travis/pdo/pgsql.phpunit.xml
index e68c3e0..77e1493 100644
--- a/tests/travis/pdo/pgsql.phpunit.xml
+++ b/tests/travis/pdo/pgsql.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../../codeigniter/core</directory>
-			<directory suffix="test.php">../../codeigniter/helpers</directory>
-			<directory suffix="test.php">../../codeigniter/libraries</directory>
-			<directory suffix="test.php">../../codeigniter/database</directory>
+			<directory suffix="test.php">../../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/tests/travis/pdo/sqlite.phpunit.xml b/tests/travis/pdo/sqlite.phpunit.xml
index 1871f62..cdccef0 100644
--- a/tests/travis/pdo/sqlite.phpunit.xml
+++ b/tests/travis/pdo/sqlite.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../../codeigniter/core</directory>
-			<directory suffix="test.php">../../codeigniter/helpers</directory>
-			<directory suffix="test.php">../../codeigniter/libraries</directory>
-			<directory suffix="test.php">../../codeigniter/database</directory>
+			<directory suffix="test.php">../../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/tests/travis/pgsql.phpunit.xml b/tests/travis/pgsql.phpunit.xml
index ad8aede..dfc1bff 100644
--- a/tests/travis/pgsql.phpunit.xml
+++ b/tests/travis/pgsql.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../codeigniter/core</directory>
-			<directory suffix="test.php">../codeigniter/helpers</directory>
-			<directory suffix="test.php">../codeigniter/libraries</directory>
-			<directory suffix="test.php">../codeigniter/database</directory>
+			<directory suffix="test.php">../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/tests/travis/sqlite.phpunit.xml b/tests/travis/sqlite.phpunit.xml
index 628370e..3223da5 100644
--- a/tests/travis/sqlite.phpunit.xml
+++ b/tests/travis/sqlite.phpunit.xml
@@ -14,19 +14,13 @@
     </php>
 	<testsuites>
 		<testsuite name="CodeIgniter Core Test Suite">
-			<file>../codeigniter/Setup_test.php</file>
-			<directory suffix="test.php">../codeigniter/core</directory>
-			<directory suffix="test.php">../codeigniter/helpers</directory>
-			<directory suffix="test.php">../codeigniter/libraries</directory>
-			<directory suffix="test.php">../codeigniter/database</directory>
+			<directory suffix="test.php">../codeigniter</directory>
 		</testsuite>
 	</testsuites>
 	<filters>
 		<blacklist>
 			<directory suffix=".php">PEAR_INSTALL_DIR</directory>
 			<directory suffix=".php">PHP_LIBDIR</directory>
-			<directory suffix=".php">PROJECT_BASE.'tests'</directory>
-			<directory suffix=".php">'../../system/core/CodeIgniter.php'</directory>
 		</blacklist>
 	</filters>
 </phpunit>
\ No newline at end of file
diff --git a/user_guide_src/source/changelog.rst b/user_guide_src/source/changelog.rst
index d457a3f..d33a6a6 100644
--- a/user_guide_src/source/changelog.rst
+++ b/user_guide_src/source/changelog.rst
@@ -77,6 +77,7 @@
 	 -  pg_version() is now used to get the database version number, when possible.
 	 -  Added db_set_charset() support.
 	 -  Added _optimize_table() support for the :doc:`Database Utility Class <database/utilities>` (rebuilds table indexes).
+	 -  Added boolean data type support in escape().
    -  Added a constructor to the DB_result class and moved all driver-specific properties and logic out of the base DB_driver class to allow better abstraction.
    -  Removed limit() and order_by() support for UPDATE and DELETE queries in PostgreSQL driver. Postgres does not support those features.
    -  Removed protect_identifiers() and renamed internal method _protect_identifiers() to it instead - it was just an alias.