Integrated vfsStream better and made paths constants VFS-based

Signed-off-by: dchill42 <dchill42@gmail.com>
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index 88d016b..431c310 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -48,32 +48,32 @@
 
 		if (in_array($subclass, $ci_core))
 		{
-			$dir = BASEPATH.'core'.DIRECTORY_SEPARATOR;
+			$dir = SYSTEM_PATH.'core'.DIRECTORY_SEPARATOR;
 			$class = $subclass;
 		}
 		elseif (in_array($subclass, $ci_libraries))
 		{
-			$dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR;
+			$dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR;
 			$class = ($subclass === 'Driver_Library') ? 'Driver' : $subclass;
 		}
 		elseif (in_array($subclass, $ci_drivers))
 		{
-			$dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR;
+			$dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR.$subclass.DIRECTORY_SEPARATOR;
 			$class = $subclass;
 		}
 		elseif (in_array(($parent = strtok($subclass, '_')), $ci_drivers)) {
-			$dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
+			$dir = SYSTEM_PATH.'libraries'.DIRECTORY_SEPARATOR.$parent.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
 			$class = $subclass;
 		}
 		elseif (preg_match('/^CI_DB_(.+)_(driver|forge|result|utility)$/', $class, $m) && count($m) === 3)
 		{
-			$driver_path = BASEPATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
+			$driver_path = SYSTEM_PATH.'database'.DIRECTORY_SEPARATOR.'drivers'.DIRECTORY_SEPARATOR;
 			$dir = $driver_path.$m[1].DIRECTORY_SEPARATOR;
 			$file = $dir.$m[1].'_'.$m[2].'.php';
 		}
 		elseif (strpos($class, 'CI_DB') === 0)
 		{
-			$dir = BASEPATH.'database'.DIRECTORY_SEPARATOR;
+			$dir = SYSTEM_PATH.'database'.DIRECTORY_SEPARATOR;
 			$file = $dir.str_replace(array('CI_DB','active_record'), array('DB', 'active_rec'), $subclass).'.php';
 		}
 		else
diff --git a/tests/mocks/ci_testcase.php b/tests/mocks/ci_testcase.php
index eda9e1b..980e912 100644
--- a/tests/mocks/ci_testcase.php
+++ b/tests/mocks/ci_testcase.php
@@ -2,7 +2,9 @@
 
 class CI_TestCase extends PHPUnit_Framework_TestCase {
 
-	protected $ci_config;
+	public $ci_vfs_root;
+	public $ci_app_root;
+	public $ci_base_root;
 	protected $ci_instance;
 	protected static $ci_test_instance;
 
@@ -25,13 +27,18 @@
 	public function __construct()
 	{
 		parent::__construct();
-		$this->ci_config = array();
+		$this->ci_instance = new StdClass();
 	}
 
 	// --------------------------------------------------------------------
 
 	public function setUp()
 	{
+		// Setup VFS with base directories
+		$this->ci_vfs_root = vfsStream::setup();
+		$this->ci_app_root = vfsStream::newDirectory('application')->at($this->ci_vfs_root);
+		$this->ci_base_root = vfsStream::newDirectory('system')->at($this->ci_vfs_root);
+
 		if (method_exists($this, 'set_up'))
 		{
 			$this->set_up();
@@ -57,15 +64,27 @@
 
 	// --------------------------------------------------------------------
 
-	public function ci_set_config($key, $val = '')
+	public function ci_set_config($key = '', $val = '')
 	{
+		// Add test config
+		if ( ! isset($this->ci_instance->config))
+		{
+			$this->ci_instance->config = new CI_TestConfig();
+		}
+
+		// Empty key means just do setup above
+		if ($key === '')
+		{
+			return;
+		}
+
 		if (is_array($key))
 		{
-			$this->ci_config = $key;
+			$this->ci_instance->config->config = $key;
 		}
 		else
 		{
-			$this->ci_config[$key] = $val;
+			$this->ci_instance->config->config[$key] = $val;
 		}
 	}
 
@@ -73,7 +92,7 @@
 
 	public function ci_get_config()
 	{
-		return $this->ci_config;
+		return isset($this->ci_instance->config) ? $this->ci_instance->config->config : array();
 	}
 
 	// --------------------------------------------------------------------
@@ -132,7 +151,7 @@
 
 		if ( ! class_exists('CI_'.$class_name))
 		{
-			require_once BASEPATH.'core/'.$class_name.'.php';
+			require_once SYSTEM_PATH.'core/'.$class_name.'.php';
 		}
 
 		$GLOBALS[strtoupper($global_name)] = 'CI_'.$class_name;
@@ -148,6 +167,155 @@
 		$orig = $obj;
 	}
 
+	/**
+	 * Create VFS directory
+	 *
+	 * @param	string	Directory name
+	 * @param	object	Optional root to create in
+	 * @return	object	New directory object
+	 */
+	public function ci_vfs_mkdir($name, $root = NULL)
+	{
+		// Check for root
+		if ( ! $root)
+		{
+			$root = $this->ci_vfs_root;
+		}
+
+		// Return new directory object
+		return vfsStream::newDirectory($name)->at($root);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Create VFS content
+	 *
+	 * @param	string	File name
+	 * @param	string	File content
+	 * @param	object	VFS directory object
+	 * @param	mixed	Optional subdirectory path or array of subs
+	 * @return	void
+	 */
+	public function ci_vfs_create($file, $content = '', $root = NULL, $path = NULL)
+	{
+		// Check for array
+		if (is_array($file))
+		{
+			foreach ($file as $name => $content)
+			{
+				$this->ci_vfs_create($name, $content, $root, $path);
+			}
+			return;
+		}
+
+		// Assert .php extension if none given
+		if (pathinfo($file, PATHINFO_EXTENSION) == '')
+		{
+			$file .= '.php';
+		}
+
+		// Build content
+		$tree = array($file => $content);
+
+		// Check for path
+		$subs = array();
+		if ($path)
+		{
+			// Explode if not array
+			$subs = is_array($path) ? $path : explode('/', trim($path, '/'));
+		}
+
+		// Check for root
+		if ( ! $root)
+		{
+			// Use base VFS root
+			$root = $this->ci_vfs_root;
+		}
+
+		// Handle subdirectories
+		while (($dir = array_shift($subs)))
+		{
+			// See if subdir exists under current root
+			$dir_root = $root->getChild($dir);
+			if ($dir_root)
+			{
+			   	// Yes - recurse into subdir
+				$root = $dir_root;
+			}
+			else
+			{
+				// No - put subdirectory back and quit
+				array_unshift($subs, $dir);
+				break;
+			}
+		}
+
+		// Create any remaining subdirectories
+		if ($subs)
+		{
+			foreach (array_reverse($subs) as $dir)
+			{
+				// Wrap content in subdirectory for creation
+				$tree = array($dir => $tree);
+			}
+		}
+
+		// Create tree
+		vfsStream::create($tree, $root);
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Clone a real file into VFS
+	 *
+	 * @param	string	Path from base directory
+	 * @return	bool	TRUE on success, otherwise FALSE
+	 */
+	public function ci_vfs_clone($path)
+	{
+		// Get real file contents
+		$content = file_get_contents(PROJECT_BASE.$path);
+		if ($content === FALSE)
+		{
+			// Couldn't find file to clone
+			return FALSE;
+		}
+
+		$this->ci_vfs_create(basename($path), $content, NULL, dirname($path));
+		return TRUE;
+	}
+
+	// --------------------------------------------------------------------
+
+	/**
+	 * Helper to get a VFS URL path
+	 *
+	 * @param	string	Path
+	 * @param	string	Optional base path
+	 * @return	string	Path URL
+	 */
+	public function ci_vfs_path($path, $base = '')
+	{
+		// Check for base path
+		if ($base)
+		{
+			// Prepend to path
+			$path = rtrim($base, '/').'/'.ltrim($path, '/');
+
+			// Is it already in URL form?
+			if (strpos($path, '://') !== FALSE)
+			{
+				// Done - return path
+				return $path;
+			}
+		}
+
+		// Trim leading slash and return URL
+		return vfsStream::url(ltrim($path, '/'));
+	}
+
 	// --------------------------------------------------------------------
 	// Internals
 	// --------------------------------------------------------------------
@@ -171,7 +339,15 @@
 
 	public function helper($name)
 	{
-		require_once(BASEPATH.'helpers/'.$name.'_helper.php');
+		require_once(SYSTEM_PATH.'helpers/'.$name.'_helper.php');
+	}
+
+	// --------------------------------------------------------------------
+
+	public function lang($name)
+	{
+		require(SYSTEM_PATH.'language/english/'.$name.'_lang.php');
+		return $lang;
 	}
 
 	// --------------------------------------------------------------------
diff --git a/tests/mocks/ci_testconfig.php b/tests/mocks/ci_testconfig.php
new file mode 100644
index 0000000..eb318dd
--- /dev/null
+++ b/tests/mocks/ci_testconfig.php
@@ -0,0 +1,18 @@
+<?php
+
+class CI_TestConfig {
+
+	public $config = array();
+	public $_config_paths = array(APPPATH);
+
+	public function item($key)
+	{
+		return isset($this->config[$key]) ? $this->config[$key] : FALSE;
+	}
+
+	public function load($arg1, $arg2, $arg3)
+	{
+		return TRUE;
+	}
+
+}
diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php
index a655ee1..b001074 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -39,6 +39,30 @@
 	}
 }
 
+if ( ! function_exists('get_mimes'))
+{
+	/**
+	 * Returns the MIME types array from config/mimes.php
+	 *
+	 * @return	array
+	 */
+	function &get_mimes()
+	{
+		static $_mimes = array();
+
+		if (empty($_mimes))
+		{
+			$path = realpath(PROJECT_BASE.'application/config/mimes.php');
+			if (is_file($path))
+			{
+				$_mimes = include($path);
+			}
+		}
+
+		return $_mimes;
+	}
+}
+
 // --------------------------------------------------------------------
 
 if ( ! function_exists('load_class'))
@@ -166,4 +190,4 @@
 	{
 		return TRUE;
 	}
-}
\ No newline at end of file
+}
diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php
index 9eb7825..7ea4da3 100644
--- a/tests/mocks/core/loader.php
+++ b/tests/mocks/core/loader.php
@@ -3,36 +3,6 @@
 class Mock_Core_Loader extends CI_Loader {
 
 	/**
-	 * Since we use paths to load up models, views, etc, we need the ability to
-	 * mock up the file system so when core tests are run, we aren't mucking
-	 * in the application directory. This will give finer grained control over
-	 * these tests. Also, by mocking the system directory, we eliminate dependency
-	 * on any other classes so errors in libraries, helpers, etc. don't give false
-	 * negatives for the actual loading process. So yeah, while this looks odd,
-	 * I need to overwrite protected class vars in the loader. So here we go...
-	 *
-	 * @covers CI_Loader::__construct()
-	 */
-	public function __construct()
-	{
-		// Create VFS tree of loader locations
-		$this->root = vfsStream::setup();
-		$this->app_root = vfsStream::newDirectory('application')->at($this->root);
-		$this->base_root = vfsStream::newDirectory('system')->at($this->root);
-
-		// Get VFS app and base path URLs
-		$this->app_path = vfsStream::url('application').'/';
-		$this->base_path = vfsStream::url('system').'/';
-
-		// Set loader paths with VFS URLs
-		$this->_ci_ob_level  		= ob_get_level();
-		$this->_ci_library_paths	= array($this->app_path, $this->base_path);
-		$this->_ci_helper_paths 	= array($this->app_path, $this->base_path);
-		$this->_ci_model_paths 		= array($this->app_path);
-		$this->_ci_view_paths 		= array($this->app_path.'views/' => TRUE);
-	}
-
-	/**
 	 * Give public access to _ci_autoloader for testing
 	 */
 	public function autoload()