summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--system/core/Loader.php12
-rw-r--r--tests/Bootstrap.php14
-rw-r--r--tests/codeigniter/core/Config_test.php52
-rw-r--r--tests/codeigniter/core/Lang_test.php2
-rw-r--r--tests/codeigniter/core/Loader_test.php301
-rw-r--r--tests/codeigniter/helpers/date_helper_test.php2
-rw-r--r--tests/codeigniter/helpers/form_helper_test.php8
-rw-r--r--tests/codeigniter/helpers/number_helper_test.php17
-rw-r--r--tests/codeigniter/helpers/text_helper_test.php1
-rw-r--r--tests/codeigniter/libraries/Encrypt_test.php7
-rw-r--r--tests/codeigniter/libraries/Parser_test.php8
-rw-r--r--tests/codeigniter/libraries/Session_test.php12
-rw-r--r--tests/codeigniter/libraries/Table_test.php8
-rw-r--r--tests/codeigniter/libraries/Typography_test.php8
-rw-r--r--tests/codeigniter/libraries/Upload_test.php57
-rw-r--r--tests/codeigniter/libraries/Useragent_test.php7
-rw-r--r--tests/mocks/autoloader.php12
-rw-r--r--tests/mocks/ci_testcase.php192
-rw-r--r--tests/mocks/ci_testconfig.php18
-rw-r--r--tests/mocks/core/common.php26
-rw-r--r--tests/mocks/core/loader.php26
21 files changed, 615 insertions, 175 deletions
diff --git a/system/core/Loader.php b/system/core/Loader.php
index 75e93608a..ed830e2dd 100644
--- a/system/core/Loader.php
+++ b/system/core/Loader.php
@@ -1140,13 +1140,16 @@ class CI_Loader {
*/
protected function _ci_autoloader()
{
- if (defined('ENVIRONMENT') && file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
+ // Get autoloader file from config path
+ $CI =& get_instance();
+ $path = reset($CI->config->_config_paths).'config/';
+ if (defined('ENVIRONMENT') && file_exists($path.ENVIRONMENT.'/autoload.php'))
{
- include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
+ include($path.ENVIRONMENT.'/autoload.php');
}
else
{
- include(APPPATH.'config/autoload.php');
+ include($path.'autoload.php');
}
if ( ! isset($autoload))
@@ -1166,7 +1169,6 @@ class CI_Loader {
// Load any custom config file
if (count($autoload['config']) > 0)
{
- $CI =& get_instance();
foreach ($autoload['config'] as $key => $val)
{
$CI->config->load($val);
@@ -1275,4 +1277,4 @@ class CI_Loader {
}
/* End of file Loader.php */
-/* Location: ./system/core/Loader.php */ \ No newline at end of file
+/* Location: ./system/core/Loader.php */
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
index 1c666d503..ea8d8aea8 100644
--- a/tests/Bootstrap.php
+++ b/tests/Bootstrap.php
@@ -8,10 +8,7 @@ $dir = realpath(dirname(__FILE__));
// Path constants
defined('PROJECT_BASE') OR define('PROJECT_BASE', realpath($dir.'/../').'/');
-defined('BASEPATH') OR define('BASEPATH', PROJECT_BASE.'system/');
-defined('APPPATH') OR define('APPPATH', PROJECT_BASE.'application/');
-defined('VIEWPATH') OR define('VIEWPATH', PROJECT_BASE.'');
-isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+defined('SYSTEM_PATH') OR define('SYSTEM_PATH', PROJECT_BASE.'system/');
// Get vfsStream either via PEAR or composer
foreach (explode(PATH_SEPARATOR, get_include_path()) as $path)
@@ -31,8 +28,17 @@ if ( ! class_exists('vfsStream') && file_exists(PROJECT_BASE.'vendor/autoload.ph
class_alias('org\bovigo\vfs\vfsStreamWrapper', 'vfsStreamWrapper');
}
+// Define CI path constants to VFS (filesystem setup in CI_TestCase::setUp)
+defined('BASEPATH') OR define('BASEPATH', vfsStream::url('system/'));
+defined('APPPATH') OR define('APPPATH', vfsStream::url('application/'));
+defined('VIEWPATH') OR define('VIEWPATH', APPPATH.'views/');
+
+// Set localhost "remote" IP
+isset($_SERVER['REMOTE_ADDR']) OR $_SERVER['REMOTE_ADDR'] = '127.0.0.1';
+
// Prep our test environment
include_once $dir.'/mocks/core/common.php';
+include_once SYSTEM_PATH.'core/common.php';
include_once $dir.'/mocks/autoloader.php';
spl_autoload_register('autoload');
diff --git a/tests/codeigniter/core/Config_test.php b/tests/codeigniter/core/Config_test.php
index 30cb90a28..7782a7898 100644
--- a/tests/codeigniter/core/Config_test.php
+++ b/tests/codeigniter/core/Config_test.php
@@ -90,4 +90,54 @@ class Config_test extends CI_TestCase {
$this->assertEquals('http://example.com/system/', $this->config->system_url());
}
-} \ No newline at end of file
+ // --------------------------------------------------------------------
+
+ public function test_load()
+ {
+ // Create VFS tree of application config files
+ $file1 = 'test.php';
+ $file2 = 'secttest';
+ $key1 = 'testconfig';
+ $val1 = 'my_value';
+ $cfg1 = array(
+ $key1 => $val1
+ );
+ $cfg2 = array(
+ 'one' => 'prime',
+ 'two' => 2,
+ 'three' => true
+ );
+ $tree = array(
+ 'application' => array(
+ 'config' => array(
+ $file1 => '<?php $config = '.var_export($cfg1, TRUE).';',
+ $file2.'.php' => '<?php $config = '.var_export($cfg2, TRUE).';'
+ )
+ )
+ );
+ $root = vfsStream::setup('root', NULL, $tree);
+
+ // Set config path with VFS URL
+ $this->config->_config_paths = array(vfsStream::url('application').'/');
+
+ // Test regular load
+ $this->assertTrue($this->config->load($file1));
+ $this->assertEquals($val1, $this->config->item($key1));
+
+ // Test section load
+ $this->assertTrue($this->config->load($file2, TRUE));
+ $this->assertEquals($cfg2, $this->config->item($file2));
+
+ // Test graceful fail
+ $this->assertFalse($this->config->load('not_config_file', FALSE, TRUE));
+
+ // Test regular fail
+ $file3 = 'absentia';
+ $this->setExpectedException(
+ 'RuntimeException',
+ 'CI Error: The configuration file '.$file3.'.php does not exist.'
+ );
+ $this->assertNull($this->config->load($file3));
+ }
+
+}
diff --git a/tests/codeigniter/core/Lang_test.php b/tests/codeigniter/core/Lang_test.php
index a410dabfa..3364362e0 100644
--- a/tests/codeigniter/core/Lang_test.php
+++ b/tests/codeigniter/core/Lang_test.php
@@ -17,6 +17,7 @@ class Lang_test extends CI_TestCase {
public function test_load()
{
+ $this->ci_vfs_clone('system/language/english/profiler_lang.php');
$this->assertTrue($this->lang->load('profiler', 'english'));
$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
}
@@ -25,6 +26,7 @@ class Lang_test extends CI_TestCase {
public function test_load_with_unspecified_language()
{
+ $this->ci_vfs_clone('system/language/english/profiler_lang.php');
$this->assertTrue($this->lang->load('profiler'));
$this->assertEquals('URI STRING', $this->lang->line('profiler_uri_string'));
}
diff --git a/tests/codeigniter/core/Loader_test.php b/tests/codeigniter/core/Loader_test.php
index fdea962b7..69b2afb63 100644
--- a/tests/codeigniter/core/Loader_test.php
+++ b/tests/codeigniter/core/Loader_test.php
@@ -9,63 +9,122 @@ class Loader_test extends CI_TestCase {
// Instantiate a new loader
$this->load = new Mock_Core_Loader();
- // mock up a ci instance
- $this->ci_obj = new stdClass;
+ // Get CI instance
+ $this->ci_obj = $this->ci_instance();
- // Fix get_instance()
- $this->ci_instance($this->ci_obj);
+ // Set subclass prefix
+ $this->ci_set_config('subclass_prefix', 'MY_');
}
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::library
+ */
public function test_library()
{
- $this->_setup_config_mock();
+ // Create libraries directory with test library
+ $lib = 'unit_test_lib';
+ $class = 'CI_'.ucfirst($lib);
+ $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_base_root, 'libraries');
// Test loading as an array.
- $this->assertNull($this->load->library(array('table')));
- $this->assertTrue(class_exists('CI_Table'), 'Table class exists');
- $this->assertAttributeInstanceOf('CI_Table', 'table', $this->ci_obj);
+ $this->assertNull($this->load->library(array($lib)));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+ $this->assertAttributeInstanceOf($class, $lib, $this->ci_obj);
// Test no lib given
- $this->assertEquals(FALSE, $this->load->library());
+ $this->assertFalse($this->load->library());
// Test a string given to params
- $this->assertEquals(NULL, $this->load->library('table', ' '));
+ $this->assertNull($this->load->library($lib, ' '));
}
// --------------------------------------------------------------------
- public function test_load_library_in_application_dir()
+ /**
+ * @covers CI_Loader::library
+ */
+ public function test_library_config()
{
- $this->_setup_config_mock();
+ // Create libraries directory with test library
+ $lib = 'unit_test_config_lib';
+ $class = 'CI_'.ucfirst($lib);
+ $content = '<?php class '.$class.' { public function __construct($params) { $this->config = $params; } }';
+ $this->ci_vfs_create($lib, $content, $this->ci_base_root, 'libraries');
+
+ // Create config file
+ $cfg = array(
+ 'foo' => 'bar',
+ 'bar' => 'baz',
+ 'baz' => false
+ );
+ $this->ci_vfs_create($lib, '<?php $config = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config');
+
+ // Test object name and config
+ $obj = 'testy';
+ $this->assertNull($this->load->library($lib, NULL, $obj));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+ $this->assertAttributeInstanceOf($class, $obj, $this->ci_obj);
+ $this->assertEquals($cfg, $this->ci_obj->$obj->config);
+ }
- $content = '<?php class Super_test_library {} ';
+ // --------------------------------------------------------------------
- $model = vfsStream::newFile('Super_test_library.php')->withContent($content)->at($this->load->libs_dir);
- $this->assertNull($this->load->library('super_test_library'));
+ /**
+ * @covers CI_Loader::library
+ */
+ public function test_load_library_in_application_dir()
+ {
+ // Create libraries directory in app path with test library
+ $lib = 'super_test_library';
+ $class = ucfirst($lib);
+ $this->ci_vfs_create($lib, '<?php class '.$class.' { }', $this->ci_app_root, 'libraries');
+
+ // Load library
+ $this->assertNull($this->load->library($lib));
// Was the model class instantiated.
- $this->assertTrue(class_exists('Super_test_library'));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+ $this->assertAttributeInstanceOf($class, $lib, $this->ci_obj);
}
// --------------------------------------------------------------------
- private function _setup_config_mock()
+ /**
+ * @covers CI_Loader::driver
+ */
+ public function test_driver()
{
- // Mock up a config object until we
- // figure out how to test the library configs
- $config = $this->getMock('CI_Config', NULL, array(), '', FALSE);
- $config->expects($this->any())
- ->method('load')
- ->will($this->returnValue(TRUE));
+ // Create libraries directory with test driver
+ $driver = 'unit_test_driver';
+ $dir = ucfirst($driver);
+ $class = 'CI_'.$dir;
+ $content = '<?php class '.$class.' { } ';
+ $this->ci_vfs_create($driver, $content, $this->ci_base_root, 'libraries/'.$dir);
- // Add the mock to our stdClass
- $this->ci_instance_var('config', $config);
+ // Test loading as an array.
+ $this->assertNull($this->load->driver(array($driver)));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+ $this->assertAttributeInstanceOf($class, $driver, $this->ci_obj);
+
+ // Test loading as a library with a name
+ $obj = 'testdrive';
+ $this->assertNull($this->load->library($driver, NULL, $obj));
+ $this->assertAttributeInstanceOf($class, $obj, $this->ci_obj);
+
+ // Test no driver given
+ $this->assertFalse($this->load->driver());
+
+ // Test a string given to params
+ $this->assertNull($this->load->driver($driver, ' '));
}
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::model
+ */
public function test_non_existent_model()
{
$this->setExpectedException(
@@ -79,20 +138,23 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
/**
- * @coverts CI_Loader::model
+ * @covers CI_Loader::model
*/
public function test_models()
{
$this->ci_set_core_class('model', 'CI_Model');
- $content = '<?php class Unit_test_model extends CI_Model {} ';
-
- $model = vfsStream::newFile('unit_test_model.php')->withContent($content)->at($this->load->models_dir);
+ // Create models directory with test model
+ $model = 'unit_test_model';
+ $class = ucfirst($model);
+ $content = '<?php class '.$class.' extends CI_Model {} ';
+ $this->ci_vfs_create($model, $content, $this->ci_app_root, 'models');
- $this->assertNull($this->load->model('unit_test_model'));
+ // Load model
+ $this->assertNull($this->load->model($model));
// Was the model class instantiated.
- $this->assertTrue(class_exists('Unit_test_model'));
+ $this->assertTrue(class_exists($class));
// Test no model given
$this->assertNull($this->load->model(''));
@@ -109,26 +171,27 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
/**
- * @coverts CI_Loader::view
+ * @covers CI_Loader::view
*/
public function test_load_view()
{
$this->ci_set_core_class('output', 'CI_Output');
+ // Create views directory with test view
+ $view = 'unit_test_view';
$content = 'This is my test page. <?php echo $hello; ?>';
- $view = vfsStream::newFile('unit_test_view.php')->withContent($content)->at($this->load->views_dir);
+ $this->ci_vfs_create($view, $content, $this->ci_app_root, 'views');
// Use the optional return parameter in this test, so the view is not
// run through the output class.
- $this->assertEquals('This is my test page. World!',
- $this->load->view('unit_test_view', array('hello' => "World!"), TRUE));
-
+ $out = $this->load->view($view, array('hello' => "World!"), TRUE);
+ $this->assertEquals('This is my test page. World!', $out);
}
// --------------------------------------------------------------------
/**
- * @coverts CI_Loader::view
+ * @covers CI_Loader::view
*/
public function test_non_existent_view()
{
@@ -142,16 +205,22 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::file
+ */
public function test_file()
{
+ // Create views directory with test file
+ $dir = 'views';
+ $file = 'ci_test_mock_file';
$content = 'Here is a test file, which we will load now.';
- $file = vfsStream::newFile('ci_test_mock_file.php')->withContent($content)->at($this->load->views_dir);
+ $this->ci_vfs_create($file, $content, $this->ci_app_root, $dir);
// Just like load->view(), take the output class out of the mix here.
- $load = $this->load->file(vfsStream::url('application').'/views/ci_test_mock_file.php', TRUE);
-
- $this->assertEquals($content, $load);
+ $out = $this->load->file(APPPATH.$dir.'/'.$file.'.php', TRUE);
+ $this->assertEquals($content, $out);
+ // Test non-existent file
$this->setExpectedException(
'RuntimeException',
'CI Error: Unable to load the requested file: ci_test_file_not_exists'
@@ -162,6 +231,9 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::vars
+ */
public function test_vars()
{
$this->assertNull($this->load->vars(array('foo' => 'bar')));
@@ -170,10 +242,22 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::helper
+ */
public function test_helper()
{
- $this->assertEquals(NULL, $this->load->helper('array'));
+ // Create helper directory in app path with test helper
+ $helper = 'test';
+ $func = '_my_helper_test_func';
+ $content = '<?php function '.$func.'() { return true; } ';
+ $this->ci_vfs_create($helper.'_helper', $content, $this->ci_app_root, 'helpers');
+
+ // Load helper
+ $this->assertEquals(NULL, $this->load->helper($helper));
+ $this->assertTrue(function_exists($func), $func.' does not exist');
+ // Test non-existent helper
$this->setExpectedException(
'RuntimeException',
'CI Error: Unable to load the requested file: helpers/bad_helper.php'
@@ -184,9 +268,31 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::helper
+ */
public function test_loading_multiple_helpers()
{
- $this->assertEquals(NULL, $this->load->helpers(array('file', 'array', 'string')));
+ // Create helper directory in base path with test helpers
+ $helpers = array();
+ $funcs = array();
+ $files = array();
+ for ($i = 1; $i <= 3; ++$i) {
+ $helper = 'test'.$i;
+ $helpers[] = $helper;
+ $func = '_my_helper_test_func'.$i;
+ $funcs[] = $func;
+ $files[$helper.'_helper'] = '<?php function '.$func.'() { return true; } ';
+ }
+ $this->ci_vfs_create($files, NULL, $this->ci_base_root, 'helpers');
+
+ // Load helpers
+ $this->assertEquals(NULL, $this->load->helpers($helpers));
+
+ // Verify helper existence
+ foreach ($funcs as $func) {
+ $this->assertTrue(function_exists($func), $func.' does not exist');
+ }
}
// --------------------------------------------------------------------
@@ -198,24 +304,117 @@ class Loader_test extends CI_TestCase {
// --------------------------------------------------------------------
+ /**
+ * @covers CI_Loader::add_package_path
+ * @covers CI_Loader::get_package_paths
+ * @covers CI_Loader::remove_package_path
+ */
+ public function test_packages()
+ {
+ // Create third-party directory in app path with model
+ $dir = 'third-party';
+ $lib = 'unit_test_package';
+ $class = 'CI_'.ucfirst($lib);
+ $content = '<?php class '.$class.' { } ';
+ $this->ci_vfs_create($lib, $content, $this->ci_app_root, $dir);
+
+ // Test failed load without path
+ $this->setExpectedException(
+ 'RuntimeException',
+ 'CI Error: Unable to load the requested class: '.$lib
+ );
+ $this->load->library($lib);
+
+ // Clear exception and get paths
+ $this->setExpectedException(NULL);
+ $paths = $this->load->get_package_paths(TRUE);
+
+ // Add path and verify
+ $path = APPPATH.$dir;
+ $this->assertNull($this->load->add_package_path($path));
+ $this->assertContains($path, $this->load->get_package_paths(TRUE));
+
+ // Test successful load
+ $this->assertNull($this->load->library($lib));
+ $this->assertTrue(class_exists($class), $class.' does not exist');
+
+ // Remove path and verify restored paths
+ $this->assertNull($this->load->remove_package_path($path));
+ $this->assertEquals($paths, $this->load->get_package_paths(TRUE));
+ }
+
+ // --------------------------------------------------------------------
+
+ /**
+ * @covers CI_Loader::config
+ */
public function test_load_config()
{
- $this->_setup_config_mock();
$this->assertNull($this->load->config('config', FALSE));
}
// --------------------------------------------------------------------
- public function test_load_bad_config()
+ /**
+ * @covers CI_Loader::_ci_autoloader
+ */
+ public function test_autoloader()
{
- $this->_setup_config_mock();
-
- $this->setExpectedException(
- 'RuntimeException',
- 'CI Error: The configuration file foobar.php does not exist.'
+ // Create helper directory in app path with test helper
+ $helper = 'autohelp';
+ $hlp_func = '_autohelp_test_func';
+ $content = '<?php function '.$hlp_func.'() { return true; } ';
+ $this->ci_vfs_create($helper.'_helper', $content, $this->ci_app_root, 'helpers');
+
+ // Create libraries directory in base path with test library
+ $lib = 'autolib';
+ $lib_class = 'CI_'.ucfirst($lib);
+ $this->ci_vfs_create($lib, '<?php class '.$lib_class.' { }', $this->ci_base_root, 'libraries');
+
+ // Create test driver
+ $drv = 'autodrv';
+ $subdir = ucfirst($drv);
+ $drv_class = 'CI_'.$subdir;
+ $this->ci_vfs_create($drv, '<?php class '.$drv_class.' { }', $this->ci_base_root, 'libraries/'.$subdir);
+
+ // Create package directory in app path with model
+ $dir = 'testdir';
+ $path = APPPATH.$dir.'/';
+ $model = 'automod';
+ $mod_class = ucfirst($model);
+ $this->ci_vfs_create($model, '<?php class '.$mod_class.' { }', $this->ci_app_root, $dir.'/models');
+
+ // Create autoloader config
+ $cfg = array(
+ 'packages' => array($path),
+ 'helper' => array($helper),
+ 'libraries' => array($lib),
+ 'drivers' => array($drv),
+ 'model' => array($model),
+ 'config' => array()
);
+ $this->ci_vfs_create('autoload', '<?php $autoload = '.var_export($cfg, TRUE).';', $this->ci_app_root, 'config');
+
+ // Run autoloader
+ $this->load->autoload();
+
+ // Verify path
+ $this->assertContains($path, $this->load->get_package_paths());
+
+ // Verify helper
+ $this->assertTrue(function_exists($hlp_func), $hlp_func.' does not exist');
+
+ // Verify library
+ $this->assertTrue(class_exists($lib_class), $lib_class.' does not exist');
+ $this->assertAttributeInstanceOf($lib_class, $lib, $this->ci_obj);
+
+ // Verify driver
+ $this->assertTrue(class_exists($drv_class), $drv_class.' does not exist');
+ $this->assertAttributeInstanceOf($drv_class, $drv, $this->ci_obj);
- $this->load->config('foobar', FALSE);
+ // Verify model
+ $this->assertTrue(class_exists($mod_class), $mod_class.' does not exist');
+ $this->assertAttributeInstanceOf($mod_class, $model, $this->ci_obj);
}
} \ No newline at end of file
diff --git a/tests/codeigniter/helpers/date_helper_test.php b/tests/codeigniter/helpers/date_helper_test.php
index 9feade71c..1458acd3e 100644
--- a/tests/codeigniter/helpers/date_helper_test.php
+++ b/tests/codeigniter/helpers/date_helper_test.php
@@ -168,6 +168,8 @@ class Date_helper_test extends CI_TestCase {
public function test_timespan()
{
+ $this->ci_vfs_clone('system/language/english/date_lang.php');
+
$loader_cls = $this->ci_core_class('load');
$this->ci_instance_var('load', new $loader_cls);
diff --git a/tests/codeigniter/helpers/form_helper_test.php b/tests/codeigniter/helpers/form_helper_test.php
index 1a30ed993..48628d2e5 100644
--- a/tests/codeigniter/helpers/form_helper_test.php
+++ b/tests/codeigniter/helpers/form_helper_test.php
@@ -1,10 +1,12 @@
<?php
-require BASEPATH . 'core/Common.php';
-require BASEPATH . 'helpers/form_helper.php';
-
class Form_helper_test extends CI_TestCase
{
+ public function set_up()
+ {
+ $this->helper('form');
+ }
+
public function test_form_hidden()
{
$expected = <<<EOH
diff --git a/tests/codeigniter/helpers/number_helper_test.php b/tests/codeigniter/helpers/number_helper_test.php
index ef6aae138..817db2c7e 100644
--- a/tests/codeigniter/helpers/number_helper_test.php
+++ b/tests/codeigniter/helpers/number_helper_test.php
@@ -11,31 +11,18 @@ class Number_helper_test extends CI_TestCase {
// Mock away load, too much going on in there,
// we'll just check for the expected parameter
-
$lang = $this->getMock($lang_cls, array('load'));
$lang->expects($this->once())
->method('load')
->with($this->equalTo('number'));
// Assign the proper language array
-
- $lang->language = $this->_get_lang('number');
+ $lang->language = $this->lang('number');
// We don't have a controller, so just create
// a cheap class to act as our super object.
// Make sure it has a lang attribute.
-
- $obj = new stdClass;
- $obj->lang = $lang;
- $this->ci_instance($obj);
- }
-
- // Quick helper to actually grab the language
- // file. Consider moving this to ci_testcase?
- public function _get_lang($name)
- {
- require BASEPATH.'language/english/'.$name.'_lang.php';
- return $lang;
+ $this->ci_instance_var('lang', $lang);
}
public function test_byte_format()
diff --git a/tests/codeigniter/helpers/text_helper_test.php b/tests/codeigniter/helpers/text_helper_test.php
index f131469cb..d75d26208 100644
--- a/tests/codeigniter/helpers/text_helper_test.php
+++ b/tests/codeigniter/helpers/text_helper_test.php
@@ -64,6 +64,7 @@ class Text_helper_test extends CI_TestCase {
public function test_convert_accented_characters()
{
+ $this->ci_vfs_clone('application/config/foreign_chars.php');
$this->assertEquals('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ'));
$this->assertEquals('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü'));
}
diff --git a/tests/codeigniter/libraries/Encrypt_test.php b/tests/codeigniter/libraries/Encrypt_test.php
index 153a25e1d..998d806b3 100644
--- a/tests/codeigniter/libraries/Encrypt_test.php
+++ b/tests/codeigniter/libraries/Encrypt_test.php
@@ -4,11 +4,8 @@ class Encrypt_test extends CI_TestCase {
public function set_up()
{
- $obj = new stdClass;
- $obj->encrypt = new Mock_Libraries_Encrypt();
-
- $this->ci_instance($obj);
- $this->encrypt = $obj->encrypt;
+ $this->encrypt = new Mock_Libraries_Encrypt();
+ $this->ci_instance_var('encrypt', $this->encrypt);
$this->ci_set_config('encryption_key', "Encryptin'glike@boss!");
$this->msg = 'My secret message';
diff --git a/tests/codeigniter/libraries/Parser_test.php b/tests/codeigniter/libraries/Parser_test.php
index b68f44a33..394c22692 100644
--- a/tests/codeigniter/libraries/Parser_test.php
+++ b/tests/codeigniter/libraries/Parser_test.php
@@ -4,12 +4,8 @@ class Parser_test extends CI_TestCase {
public function set_up()
{
- $obj = new stdClass;
- $obj->parser = new Mock_Libraries_Parser();
-
- $this->ci_instance($obj);
-
- $this->parser = $obj->parser;
+ $this->parser = new Mock_Libraries_Parser();
+ $this->ci_instance_var('parser', $this->parser);
}
// --------------------------------------------------------------------
diff --git a/tests/codeigniter/libraries/Session_test.php b/tests/codeigniter/libraries/Session_test.php
index 60d3a5b30..14469f7fa 100644
--- a/tests/codeigniter/libraries/Session_test.php
+++ b/tests/codeigniter/libraries/Session_test.php
@@ -29,13 +29,15 @@ class Session_test extends CI_TestCase {
$_COOKIE = array();
// Establish necessary support classes
- $obj = new stdClass;
$cfg = $this->ci_core_class('cfg');
- $obj->config = new $cfg();
$ldr = $this->ci_core_class('load');
- $obj->load = new $ldr();
- $obj->input = new Mock_Core_Input(NULL, NULL);
- $this->ci_instance($obj);
+ $ci = $this->ci_instance();
+ $ci->config = new $cfg();
+ $ci->load = new $ldr();
+ $ci->input = new Mock_Core_Input(NULL, NULL);
+
+ // Make sure string helper is available
+ $this->ci_vfs_clone('system/helpers/string_helper.php');
// Attach session instance locally
$config = array(
diff --git a/tests/codeigniter/libraries/Table_test.php b/tests/codeigniter/libraries/Table_test.php
index edfc83dd0..ce04b6a6d 100644
--- a/tests/codeigniter/libraries/Table_test.php
+++ b/tests/codeigniter/libraries/Table_test.php
@@ -4,12 +4,8 @@ class Table_test extends CI_TestCase {
public function set_up()
{
- $obj = new stdClass;
- $obj->table = new Mock_Libraries_Table();
-
- $this->ci_instance($obj);
-
- $this->table = $obj->table;
+ $this->table = new Mock_Libraries_Table();
+ $this->ci_instance_var('table', $this->table);
}
// Setter Methods
diff --git a/tests/codeigniter/libraries/Typography_test.php b/tests/codeigniter/libraries/Typography_test.php
index eb6dacb73..5dba06243 100644
--- a/tests/codeigniter/libraries/Typography_test.php
+++ b/tests/codeigniter/libraries/Typography_test.php
@@ -4,12 +4,8 @@ class Typography_test extends CI_TestCase {
public function set_up()
{
- $obj = new stdClass;
- $obj->type = new Mock_Libraries_Typography();
-
- $this->ci_instance($obj);
-
- $this->type = $obj->type;
+ $this->type = new Mock_Libraries_Typography();
+ $this->ci_instance('type', $this->type);
}
// --------------------------------------------------------------------
diff --git a/tests/codeigniter/libraries/Upload_test.php b/tests/codeigniter/libraries/Upload_test.php
index d79a3ffc9..827942773 100644
--- a/tests/codeigniter/libraries/Upload_test.php
+++ b/tests/codeigniter/libraries/Upload_test.php
@@ -4,18 +4,11 @@ class Upload_test extends CI_TestCase {
function set_up()
{
- $obj = new stdClass;
- $obj->upload = new Mock_Libraries_Upload();
- $obj->security = new Mock_Core_Security();
- $obj->lang = new Mock_Core_Lang();
-
- $this->ci_instance($obj);
- $this->upload = $obj->upload;
-
- vfsStreamWrapper::register();
- vfsStreamWrapper::setRoot(new vfsStreamDirectory('testDir'));
-
- $this->_test_dir = vfsStreamWrapper::getRoot();
+ $ci = $this->ci_instance();
+ $ci->upload = new Mock_Libraries_Upload();
+ $ci->security = new Mock_Core_Security();
+ $ci->lang = new Mock_Core_Lang();
+ $this->upload = $ci->upload;
}
function test_do_upload()
@@ -64,11 +57,15 @@ class Upload_test extends CI_TestCase {
function test_set_filename()
{
- $file1 = vfsStream::newFile('hello-world.txt')->withContent('Hello world.')->at($this->_test_dir);
+ $dir = 'uploads';
+ $isnew = 'helloworld.txt';
+ $exists = 'hello-world.txt';
+ $this->ci_vfs_create($exists, 'Hello world.', $this->ci_app_root, $dir);
+ $path = $this->ci_vfs_path($dir.'/', APPPATH);
$this->upload->file_ext = '.txt';
- $this->assertEquals('helloworld.txt', $this->upload->set_filename(vfsStream::url('testDir').'/', 'helloworld.txt'));
- $this->assertEquals('hello-world1.txt', $this->upload->set_filename(vfsStream::url('testDir').'/', 'hello-world.txt'));
+ $this->assertEquals($isnew, $this->upload->set_filename($path, $isnew));
+ $this->assertEquals('hello-world1.txt', $this->upload->set_filename($path, $exists));
}
function test_set_max_filesize()
@@ -107,7 +104,7 @@ class Upload_test extends CI_TestCase {
function test_set_image_properties()
{
$this->upload->file_type = 'image/gif';
- $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif');
$props = array(
'image_width' => 170,
@@ -156,7 +153,7 @@ class Upload_test extends CI_TestCase {
$this->assertTrue($this->upload->is_allowed_filetype(FALSE));
$this->assertTrue($this->upload->is_allowed_filetype(TRUE));
- $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif');
$this->upload->file_ext = '.gif';
$this->upload->file_type = 'image/gif';
$this->assertTrue($this->upload->is_allowed_filetype());
@@ -179,7 +176,7 @@ class Upload_test extends CI_TestCase {
$this->assertTrue($this->upload->is_allowed_dimensions());
$this->upload->file_type = 'image/gif';
- $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif');
$this->upload->max_width = 10;
$this->assertFalse($this->upload->is_allowed_dimensions());
@@ -197,7 +194,9 @@ class Upload_test extends CI_TestCase {
$this->upload->upload_path = '';
$this->assertFalse($this->upload->validate_upload_path());
- $this->upload->upload_path = vfsStream::url('testDir');
+ $dir = 'uploads';
+ $this->ci_vfs_mkdir($dir);
+ $this->upload->upload_path = $this->ci_vfs_path($dir);
$this->assertTrue($this->upload->validate_upload_path());
}
@@ -222,20 +221,24 @@ class Upload_test extends CI_TestCase {
function test_do_xss_clean()
{
- $file1 = vfsStream::newFile('file1.txt')->withContent('The billy goat was waiting for them.')->at($this->_test_dir);
- $file2 = vfsStream::newFile('file2.txt')->at($this->_test_dir);
- $file3 = vfsStream::newFile('file3.txt')->withContent('<script type="text/javascript">alert("Boo! said the billy goat")</script>')->at($this->_test_dir);
-
- $this->upload->file_temp = vfsStream::url('file1.txt');
+ $dir = 'uploads';
+ $file1 = 'file1.txt';
+ $file2 = 'file2.txt';
+ $file3 = 'file3.txt';
+ $this->ci_vfs_create($file1, 'The billy goat was waiting for them.', $this->ci_vfs_root, $dir);
+ $this->ci_vfs_create($file2, '', $this->ci_vfs_root, $dir);
+ $this->ci_vfs_create($file3, '<script type="text/javascript">alert("Boo! said the billy goat")</script>', $this->ci_vfs_root, $dir);
+
+ $this->upload->file_temp = $this->ci_vfs_path($file1, $dir);
$this->assertTrue($this->upload->do_xss_clean());
- $this->upload->file_temp = vfsStream::url('file2.txt');
+ $this->upload->file_temp = $this->ci_vfs_path($file2, $dir);
$this->assertFalse($this->upload->do_xss_clean());
- $this->upload->file_temp = vfsStream::url('file3.txt');
+ $this->upload->file_temp = $this->ci_vfs_path($file3, $dir);
$this->assertFalse($this->upload->do_xss_clean());
- $this->upload->file_temp = 'tests/mocks/uploads/ci_logo.gif';
+ $this->upload->file_temp = realpath(PROJECT_BASE.'tests/mocks/uploads/ci_logo.gif');
$this->assertTrue($this->upload->do_xss_clean());
}
diff --git a/tests/codeigniter/libraries/Useragent_test.php b/tests/codeigniter/libraries/Useragent_test.php
index 89383f807..e3726554e 100644
--- a/tests/codeigniter/libraries/Useragent_test.php
+++ b/tests/codeigniter/libraries/Useragent_test.php
@@ -10,12 +10,11 @@ class UserAgent_test extends CI_TestCase {
// set a baseline user agent
$_SERVER['HTTP_USER_AGENT'] = $this->_user_agent;
- $obj = new stdClass;
- $obj->agent = new Mock_Libraries_UserAgent();
+ $this->ci_vfs_clone('application/config/user_agents.php');
- $this->ci_instance($obj);
+ $this->agent = new Mock_Libraries_UserAgent();
- $this->agent = $obj->agent;
+ $this->ci_instance_var('agent', $this->agent);
}
// --------------------------------------------------------------------
diff --git a/tests/mocks/autoloader.php b/tests/mocks/autoloader.php
index 88d016bba..431c310d4 100644
--- a/tests/mocks/autoloader.php
+++ b/tests/mocks/autoloader.php
@@ -48,32 +48,32 @@ function autoload($class)
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 eda9e1b60..980e912c5 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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
// --------------------------------------------------------------------
- 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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
$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 @@ class CI_TestCase extends PHPUnit_Framework_TestCase {
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 000000000..eb318ddeb
--- /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 a655ee1db..b001074c8 100644
--- a/tests/mocks/core/common.php
+++ b/tests/mocks/core/common.php
@@ -39,6 +39,30 @@ if ( ! function_exists('config_item'))
}
}
+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 @@ if ( ! function_exists('set_status_header'))
{
return TRUE;
}
-} \ No newline at end of file
+}
diff --git a/tests/mocks/core/loader.php b/tests/mocks/core/loader.php
index 53d88d55b..7ea4da369 100644
--- a/tests/mocks/core/loader.php
+++ b/tests/mocks/core/loader.php
@@ -3,29 +3,11 @@
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()
+ * Give public access to _ci_autoloader for testing
*/
- public function __construct()
+ public function autoload()
{
- 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);
+ $this->_ci_autoloader();
}
-} \ No newline at end of file
+}