diff options
author | Andrey Andreev <narf@bofh.bg> | 2012-04-03 19:21:39 +0200 |
---|---|---|
committer | Andrey Andreev <narf@bofh.bg> | 2012-04-03 19:21:39 +0200 |
commit | 320d37c090cbc1497d3951f64da1c16e86bae609 (patch) | |
tree | 51e1bf36e4d63e233e0b9b550420805d65548945 /tests/mocks | |
parent | 31cf46eaec3b4613d5b46f9caed8bdd346b581cc (diff) | |
parent | 78f55772adb86b48d0d50572545c24c18f528ff9 (diff) |
Merge upstream branch
Diffstat (limited to 'tests/mocks')
-rw-r--r-- | tests/mocks/autoloader.php | 79 | ||||
-rw-r--r-- | tests/mocks/ci_testcase.php | 196 | ||||
-rw-r--r-- | tests/mocks/core/common.php | 132 | ||||
-rw-r--r-- | tests/mocks/core/loader.php | 30 | ||||
-rw-r--r-- | tests/mocks/core/uri.php | 25 | ||||
-rwxr-xr-x | tests/mocks/database/ci_test.sqlite | bin | 0 -> 17408 bytes | |||
-rw-r--r-- | tests/mocks/database/config/mysql.php | 34 | ||||
-rw-r--r-- | tests/mocks/database/config/pgsql.php | 34 | ||||
-rw-r--r-- | tests/mocks/database/config/sqlite.php | 35 | ||||
-rw-r--r-- | tests/mocks/database/db.php | 101 | ||||
-rw-r--r-- | tests/mocks/database/schema/.gitkeep | 0 | ||||
-rw-r--r-- | tests/mocks/libraries/parser.php | 3 | ||||
-rw-r--r-- | tests/mocks/libraries/table.php | 15 | ||||
-rw-r--r-- | tests/mocks/libraries/typography.php | 3 | ||||
-rw-r--r-- | tests/mocks/libraries/useragent.php | 3 |
15 files changed, 690 insertions, 0 deletions
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php new file mode 100644 index 000000000..dd5929206 --- /dev/null +++ b/tests/mocks/autoloader.php @@ -0,0 +1,79 @@ +<?php + +// This autoloader provide convinient way to working with mock object +// make the test looks natural. This autoloader support cascade file loading as well +// within mocks directory. +// +// 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... +function autoload($class) +{ + $dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR; + + $ci_core = array( + 'Benchmark', 'Config', 'Controller', + 'Exceptions', 'Hooks', 'Input', + 'Lang', 'Loader', 'Model', + 'Output', 'Router', 'Security', + 'URI', 'Utf8', + ); + + $ci_libraries = array( + 'Calendar', 'Cart', 'Driver', + 'Email', 'Encrypt', 'Form_validation', + 'Ftp', 'Image_lib', 'Javascript', + 'Log', 'Migration', 'Pagination', + 'Parser', 'Profiler', 'Session', + 'Table', 'Trackback', 'Typography', + 'Unit_test', 'Upload', 'User_agent', + 'Xmlrpc', 'Zip', + ); + + if (strpos($class, 'Mock_') === 0) + { + $class = str_replace(array('Mock_', '_'), array('', DIRECTORY_SEPARATOR), $class); + $class = strtolower($class); + } + elseif (strpos($class, 'CI_') === 0) + { + $fragments = explode('_', $class, 2); + $subclass = next($fragments); + + if (in_array($subclass, $ci_core)) + { + $dir = BASEPATH.'core'.DIRECTORY_SEPARATOR; + $class = $subclass; + } + elseif (in_array($subclass, $ci_libraries)) + { + $dir = BASEPATH.'libraries'.DIRECTORY_SEPARATOR; + $class = $subclass; + } + else + { + $class = strtolower($class); + } + } + + $file = $dir.$class.'.php'; + + if ( ! file_exists($file)) + { + $trace = debug_backtrace(); + + // If the autoload call came from `class_exists` or `file_exists`, + // we skipped and return FALSE + if ($trace[2]['function'] == 'class_exists' OR $trace[2]['function'] == 'file_exists') + { + return FALSE; + } + + throw new InvalidArgumentException("Unable to load $class."); + } + + include_once($file); +}
\ No newline at end of file diff --git a/tests/mocks/ci_testcase.php b/tests/mocks/ci_testcase.php new file mode 100644 index 000000000..f327e6b07 --- /dev/null +++ b/tests/mocks/ci_testcase.php @@ -0,0 +1,196 @@ +<?php + +class CI_TestCase extends PHPUnit_Framework_TestCase { + + protected $ci_config; + protected $ci_instance; + protected static $ci_test_instance; + + private $global_map = array( + 'benchmark' => 'bm', + 'config' => 'cfg', + 'hooks' => 'ext', + 'utf8' => 'uni', + 'router' => 'rtr', + 'output' => 'out', + 'security' => 'sec', + 'input' => 'in', + 'lang' => 'lang', + 'loader' => 'load', + 'model' => 'model' + ); + + // -------------------------------------------------------------------- + + public function __construct() + { + parent::__construct(); + + $this->ci_config = array(); + } + + // -------------------------------------------------------------------- + + public function setUp() + { + if (method_exists($this, 'set_up')) + { + $this->set_up(); + } + } + + // -------------------------------------------------------------------- + + public function tearDown() + { + if (method_exists($this, 'tear_down')) + { + $this->tear_down(); + } + } + + // -------------------------------------------------------------------- + + public static function instance() + { + return self::$ci_test_instance; + } + + // -------------------------------------------------------------------- + + function ci_set_config($key, $val = '') + { + if (is_array($key)) + { + $this->ci_config = $key; + } + else + { + $this->ci_config[$key] = $val; + } + } + + // -------------------------------------------------------------------- + + function ci_get_config() + { + return $this->ci_config; + } + + // -------------------------------------------------------------------- + + function ci_instance($obj = FALSE) + { + if ( ! is_object($obj)) + { + return $this->ci_instance; + } + + $this->ci_instance = $obj; + } + + // -------------------------------------------------------------------- + + function ci_instance_var($name, $obj = FALSE) + { + if ( ! is_object($obj)) + { + return $this->ci_instance->$name; + } + + $this->ci_instance->$name =& $obj; + } + + // -------------------------------------------------------------------- + + /** + * Grab a core class + * + * Loads the correct core class without extensions + * and returns a reference to the class name in the + * globals array with the correct key. This way the + * test can modify the variable it assigns to and + * still maintain the global. + */ + function &ci_core_class($name) + { + $name = strtolower($name); + + if (isset($this->global_map[$name])) + { + $class_name = ucfirst($name); + $global_name = $this->global_map[$name]; + } + elseif (in_array($name, $this->global_map)) + { + $class_name = ucfirst(array_search($name, $this->global_map)); + $global_name = $name; + } + else + { + throw new Exception('Not a valid core class.'); + } + + if ( ! class_exists('CI_'.$class_name)) + { + require_once BASEPATH.'core/'.$class_name.'.php'; + } + + $GLOBALS[strtoupper($global_name)] = 'CI_'.$class_name; + return $GLOBALS[strtoupper($global_name)]; + } + + // -------------------------------------------------------------------- + + // convenience function for global mocks + function ci_set_core_class($name, $obj) + { + $orig =& $this->ci_core_class($name); + $orig = $obj; + } + + // -------------------------------------------------------------------- + // Internals + // -------------------------------------------------------------------- + + /** + * Overwrite runBare + * + * PHPUnit instantiates the test classes before + * running them individually. So right before a test + * runs we set our instance. Normally this step would + * happen in setUp, but someone is bound to forget to + * call the parent method and debugging this is no fun. + */ + public function runBare() + { + self::$ci_test_instance = $this; + parent::runBare(); + } + + // -------------------------------------------------------------------- + + function helper($name) + { + require_once(BASEPATH.'helpers/'.$name.'_helper.php'); + } + + // -------------------------------------------------------------------- + + /** + * This overload is useful to create a stub, that need to have a specific method. + */ + function __call($method, $args) + { + if ($this->{$method} instanceof Closure) + { + return call_user_func_array($this->{$method},$args); + } + else + { + return parent::__call($method, $args); + } + } +} + +// EOF
\ No newline at end of file diff --git a/tests/mocks/core/common.php b/tests/mocks/core/common.php new file mode 100644 index 000000000..fc94d7fff --- /dev/null +++ b/tests/mocks/core/common.php @@ -0,0 +1,132 @@ +<?php + +// Set up the global CI functions in their most minimal core representation + +function &get_instance() +{ + $test = CI_TestCase::instance(); + $instance = $test->ci_instance(); + return $instance; +} + +// -------------------------------------------------------------------- + +function &get_config() { + $test = CI_TestCase::instance(); + $config = $test->ci_get_config(); + + return $config; +} + +function config_item($item) +{ + $config =& get_config(); + + if ( ! isset($config[$item])) + { + return FALSE; + } + + return $config[$item]; +} + +// -------------------------------------------------------------------- + +function load_class($class, $directory = 'libraries', $prefix = 'CI_') +{ + if ($directory != 'core' OR $prefix != 'CI_') + { + throw new Exception('Not Implemented: Non-core load_class()'); + } + + $test = CI_TestCase::instance(); + + $obj =& $test->ci_core_class($class); + + if (is_string($obj)) + { + throw new Exception('Bad Isolation: Use ci_set_core_class to set '.$class.''); + } + + return $obj; +} + +// This is sort of meh. Should probably be mocked up with +// controllable output, so that we can test some of our +// security code. The function itself will be tested in the +// bootstrap testsuite. +// -------------------------------------------------------------------- + +function remove_invisible_characters($str, $url_encoded = TRUE) +{ + $non_displayables = array(); + + // every control character except newline (dec 10) + // carriage return (dec 13), and horizontal tab (dec 09) + + if ($url_encoded) + { + $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 + $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 + } + + $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 + + do + { + $str = preg_replace($non_displayables, '', $str, -1, $count); + } + while ($count); + + return $str; +} + + +// Clean up error messages +// -------------------------------------------------------------------- + +function show_error($message, $status_code = 500, $heading = 'An Error Was Encountered') +{ + throw new RuntimeException('CI Error: '.$message); +} + +function show_404($page = '', $log_error = TRUE) +{ + throw new RuntimeException('CI Error: 404'); +} + +function _exception_handler($severity, $message, $filepath, $line) +{ + throw new RuntimeException('CI Exception: '.$message.' | '.$filepath.' | '.$line); +} + + +// We assume a few things about our environment ... +// -------------------------------------------------------------------- + +function is_php($version = '5.0.0') +{ + return ! (version_compare(PHP_VERSION, $version) < 0); +} + +function is_really_writable($file) +{ + return is_writable($file); +} + +function is_loaded() +{ + throw new Exception('Bad Isolation: mock up environment'); +} + +function log_message($level = 'error', $message, $php_error = FALSE) +{ + return TRUE; +} + +function set_status_header($code = 200, $text = '') +{ + return TRUE; +} + +// EOF
\ No newline at end of file diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php new file mode 100644 index 000000000..d4b29bb3d --- /dev/null +++ b/tests/mocks/core/loader.php @@ -0,0 +1,30 @@ +<?php + +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. 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() + { + vfsStreamWrapper::register(); + vfsStreamWrapper::setRoot(new vfsStreamDirectory('application')); + + $this->models_dir = vfsStream::newDirectory('models')->at(vfsStreamWrapper::getRoot()); + $this->libs_dir = vfsStream::newDirectory('libraries')->at(vfsStreamWrapper::getRoot()); + $this->helpers_dir = vfsStream::newDirectory('helpers')->at(vfsStreamWrapper::getRoot()); + $this->views_dir = vfsStream::newDirectory('views')->at(vfsStreamWrapper::getRoot()); + + $this->_ci_ob_level = ob_get_level(); + $this->_ci_library_paths = array(vfsStream::url('application').'/', BASEPATH); + $this->_ci_helper_paths = array(vfsStream::url('application').'/', BASEPATH); + $this->_ci_model_paths = array(vfsStream::url('application').'/'); + $this->_ci_view_paths = array(vfsStream::url('application').'/views/' => TRUE); + } +}
\ No newline at end of file diff --git a/tests/mocks/core/uri.php b/tests/mocks/core/uri.php new file mode 100644 index 000000000..b6946091e --- /dev/null +++ b/tests/mocks/core/uri.php @@ -0,0 +1,25 @@ +<?php + +class Mock_Core_URI extends CI_URI { + + public function __construct() + { + $test = CI_TestCase::instance(); + $cls =& $test->ci_core_class('cfg'); + + // set predictable config values + $test->ci_set_config(array( + 'index_page' => 'index.php', + 'base_url' => 'http://example.com/', + 'subclass_prefix' => 'MY_' + )); + + $this->config = new $cls; + + } + + protected function _is_cli_request() + { + return FALSE; + } +}
\ No newline at end of file diff --git a/tests/mocks/database/ci_test.sqlite b/tests/mocks/database/ci_test.sqlite Binary files differnew file mode 100755 index 000000000..37ce4f870 --- /dev/null +++ b/tests/mocks/database/ci_test.sqlite diff --git a/tests/mocks/database/config/mysql.php b/tests/mocks/database/config/mysql.php new file mode 100644 index 000000000..ace0a31b1 --- /dev/null +++ b/tests/mocks/database/config/mysql.php @@ -0,0 +1,34 @@ +<?php + +return array( + + // Typical Database configuration + 'mysql' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'travis', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'mysql', + ), + + // Database configuration with failover + 'mysql_failover' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'not_travis', + 'password' => 'wrong password', + 'database' => 'not_ci_test', + 'dbdriver' => 'mysql', + 'failover' => array( + array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'travis', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'mysql', + ), + ), + ), +);
\ No newline at end of file diff --git a/tests/mocks/database/config/pgsql.php b/tests/mocks/database/config/pgsql.php new file mode 100644 index 000000000..c06af8ce0 --- /dev/null +++ b/tests/mocks/database/config/pgsql.php @@ -0,0 +1,34 @@ +<?php + +return array( + + // Typical Database configuration + 'pgsql' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'postgres', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'postgre', + ), + + // Database configuration with failover + 'pgsql_failover' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'not_travis', + 'password' => 'wrong password', + 'database' => 'not_ci_test', + 'dbdriver' => 'postgre', + 'failover' => array( + array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'postgres', + 'password' => '', + 'database' => 'ci_test', + 'dbdriver' => 'postgre', + ), + ), + ), +);
\ No newline at end of file diff --git a/tests/mocks/database/config/sqlite.php b/tests/mocks/database/config/sqlite.php new file mode 100644 index 000000000..8665e208d --- /dev/null +++ b/tests/mocks/database/config/sqlite.php @@ -0,0 +1,35 @@ +<?php +$dbdriver = is_php('5.4') ? 'sqlite3' : 'sqlite'; + +return array( + + // Typical Database configuration + 'sqlite' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => realpath(__DIR__.'/..').'/ci_test.sqlite', + 'dbdriver' => $dbdriver, + ), + + // Database configuration with failover + 'sqlite_failover' => array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => '../not_exists.sqlite', + 'dbdriver' => $dbdriver, + 'failover' => array( + array( + 'dsn' => '', + 'hostname' => 'localhost', + 'username' => 'sqlite', + 'password' => 'sqlite', + 'database' => realpath(__DIR__.'/..').'/ci_testf.sqlite', + 'dbdriver' => $dbdriver, + ), + ), + ), +);
\ No newline at end of file diff --git a/tests/mocks/database/db.php b/tests/mocks/database/db.php new file mode 100644 index 000000000..43a0d391f --- /dev/null +++ b/tests/mocks/database/db.php @@ -0,0 +1,101 @@ +<?php + +class Mock_Database_DB { + + /** + * @var array DB configuration + */ + private $config = array(); + + /** + * Prepare database configuration skeleton + * + * @param array DB configuration to set + * @return void + */ + public function __construct($config = array()) + { + $this->config = $config; + } + + /** + * Build DSN connection string for DB driver instantiate process + * + * @param string Group name + * @return string DSN Connection string + */ + public function set_dsn($group = 'default') + { + if ( ! isset($this->config[$group])) + { + throw new InvalidArgumentException('Group '.$group.' not exists'); + } + + $params = array( + 'dbprefix' => '', + 'pconnect' => FALSE, + 'db_debug' => FALSE, + 'cache_on' => FALSE, + 'cachedir' => '', + 'char_set' => 'utf8', + 'dbcollat' => 'utf8_general_ci', + 'swap_pre' => '', + 'autoinit' => TRUE, + 'stricton' => FALSE, + ); + + $config = array_merge($this->config[$group], $params); + + if ( ! empty($config['dsn'])) + { + $dsn = $config['dsn']; + } + else + { + $dsn = $config['dbdriver'].'://'.$config['username'].':'.$config['password'] + .'@'.$config['hostname'].'/'.$config['database']; + + } + + $other_params = array_slice($config, 6); + + return $dsn.'?'.http_build_query($other_params); + } + + /** + * Return a database config array + * + * @see ./config + * @param string Driver based configuration + * @return array + */ + public static function config($driver) + { + $dir = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR; + + return include($dir.'config'.DIRECTORY_SEPARATOR.$driver.'.php'); + } + + /** + * Main DB method wrapper + * + * @param string Group or DSN string + * @param bool + * @return object + */ + public static function DB($group, $query_builder = FALSE) + { + include_once(BASEPATH.'database/DB.php'); + + try + { + $db = DB($group, $query_builder); + } + catch (Exception $e) + { + throw new InvalidArgumentException($e->getMessage()); + } + + return $db; + } +}
\ No newline at end of file diff --git a/tests/mocks/database/schema/.gitkeep b/tests/mocks/database/schema/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/mocks/database/schema/.gitkeep diff --git a/tests/mocks/libraries/parser.php b/tests/mocks/libraries/parser.php new file mode 100644 index 000000000..81dcfb37e --- /dev/null +++ b/tests/mocks/libraries/parser.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Libraries_Parser extends CI_Parser {}
\ No newline at end of file diff --git a/tests/mocks/libraries/table.php b/tests/mocks/libraries/table.php new file mode 100644 index 000000000..1a6ff8d35 --- /dev/null +++ b/tests/mocks/libraries/table.php @@ -0,0 +1,15 @@ +<?php + +class Mock_Libraries_Table extends CI_Table { + + // Overide inaccesible private or 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/libraries/typography.php b/tests/mocks/libraries/typography.php new file mode 100644 index 000000000..0f76c5745 --- /dev/null +++ b/tests/mocks/libraries/typography.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Libraries_Typography extends CI_Typography {}
\ No newline at end of file diff --git a/tests/mocks/libraries/useragent.php b/tests/mocks/libraries/useragent.php new file mode 100644 index 000000000..c957cde5b --- /dev/null +++ b/tests/mocks/libraries/useragent.php @@ -0,0 +1,3 @@ +<?php + +class Mock_Libraries_UserAgent extends CI_User_agent {}
\ No newline at end of file |