From f8e5926deba54b944b6900567e12e04343b15dc6 Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Fri, 8 Jun 2018 21:09:24 -0700 Subject: [PATCH 1/4] Fleshed out testing for array, cookie and date (such as it is) helpers --- tests/system/Helpers/ArrayHelperTest.php | 16 +++++++ tests/system/Helpers/CookieHelperTest.php | 48 ++++++++++--------- tests/system/Helpers/DateHelperTest.php | 44 +++++++++++++++++ user_guide_src/source/helpers/date_helper.rst | 47 ++++++++++++++++++ 4 files changed, 133 insertions(+), 22 deletions(-) create mode 100644 tests/system/Helpers/DateHelperTest.php create mode 100644 user_guide_src/source/helpers/date_helper.rst diff --git a/tests/system/Helpers/ArrayHelperTest.php b/tests/system/Helpers/ArrayHelperTest.php index 1db4d19f3542..09b6ecd2187f 100644 --- a/tests/system/Helpers/ArrayHelperTest.php +++ b/tests/system/Helpers/ArrayHelperTest.php @@ -90,6 +90,22 @@ public function testArrayDotWildcardWithMultipleChoices() $this->assertEquals(23, dot_array_search('foo.*.baz', $data)); } + public function testArrayDotNestedNotFound() + { + $data = [ + 'foo' => [ + 'buzz' => [ + 'fizz' => 11 + ], + 'bar' => [ + 'baz' => 23 + ] + ] + ]; + + $this->assertNull(dot_array_search('foo.*.notthere', $data)); + } + public function testArrayDotIgnoresLastWildcard() { $data = [ diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index a361721cd7e2..e1ae2dfc02a0 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -4,7 +4,7 @@ use CodeIgniter\Config\Services; use Tests\Support\HTTP\MockResponse; -final class cookieHelperTest extends \CIUnitTestCase +final class CookieHelperTest extends \CIUnitTestCase { private $name; @@ -22,6 +22,8 @@ public function setUp() Services::injectMock('response', new MockResponse(new App())); $this->response = service('response'); + $this->request = new IncomingRequest(new App(), new URI(), null, new UserAgent()); + Services::injectMock('request', $this->request); helper('cookie'); } @@ -30,14 +32,11 @@ public function setUp() public function testSetCookie() { - $this->response->setCookie($this->name, $this->value, $this->expire); - - //TODO: Find a way for set_cookie() to use the MockResponse object. - //set_cookie($this->name, $this->value, $this->expire); + set_cookie($this->name, $this->value, $this->expire); $this->assertTrue($this->response->hasCookie($this->name)); - $this->response->deleteCookie($this->name); + delete_cookie($this->name); } //-------------------------------------------------------------------- @@ -49,17 +48,16 @@ public function testSetCookieByArrayParameters() 'value' => $this->value, 'expire' => $this->expire ]; - //set_cookie($cookieAttr); - $this->response->setCookie($cookieAttr); - + set_cookie($cookieAttr); + $this->assertTrue($this->response->hasCookie($this->name, $this->value)); - $this->response->deleteCookie($this->name); + delete_cookie($this->name); } //-------------------------------------------------------------------- - public function testGetCookie() + public function testSetCookieSecured() { $pre = 'Hello, I try to'; $pst = 'your site'; @@ -68,29 +66,35 @@ public function testGetCookie() $unsecured = 'unsecured'; $secured = 'secured'; - //set_cookie($unsecured, $unsec, $this->expire); - //set_cookie($secured, $sec, $this->expire); - $this->response->setCookie($unsecured, $unsec, $this->expire); - $this->response->setCookie($secured, $sec, $this->expire); + set_cookie($unsecured, $unsec, $this->expire); + set_cookie($secured, $sec, $this->expire); $this->assertTrue($this->response->hasCookie($unsecured, $unsec)); $this->assertTrue($this->response->hasCookie($secured, $sec)); - $this->response->deleteCookie($unsecured); - $this->response->deleteCookie($secured); + delete_cookie($unsecured); + delete_cookie($secured); } //-------------------------------------------------------------------- public function testDeleteCookie() { - //set_cookie($this->name, $this->value, $this->expire); - $this->response->setCookie($this->name, $this->value, $this->expire); + set_cookie($this->name, $this->value, $this->expire); + //$this->response->setCookie($this->name, $this->value, $this->expire); - $this->response->deleteCookie($this->name); + delete_cookie($this->name); - //$this->assertEquals(get_cookie($this->name), ''); - $this->assertTrue($this->response->hasCookie($this->name)); + $this->assertEmpty($this->response->getCookie($this->name)); + } + + //-------------------------------------------------------------------- + + public function testGetCookie() + { + $_COOKIE['TEST'] = 5; + + $this->assertEquals(5, get_cookie('TEST')); } } diff --git a/tests/system/Helpers/DateHelperTest.php b/tests/system/Helpers/DateHelperTest.php new file mode 100644 index 000000000000..b718ec2fd4e4 --- /dev/null +++ b/tests/system/Helpers/DateHelperTest.php @@ -0,0 +1,44 @@ +assertLessThan(1, abs(now() - time())); + } + + //-------------------------------------------------------------------- + + public function testNowSpecific() + { + // Chicago should be two hours ahead of Vancouver + $this->assertEquals(7200,now('America/Chicago')-now('America/Vancouver')); +// $zone = 'America/Vancouver'; +// $time = new \DateTime('now', new \DateTimeZone($zone)); +// echo now($zone) . '\n'; +// echo now() . '\n'; +// echo $time->getTimestamp() . '\n'; +// +// $this->assertLessThan(1, abs(now($zone) - $time->getTimestamp())); + } + +} diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst new file mode 100644 index 000000000000..e6d451f4fee8 --- /dev/null +++ b/user_guide_src/source/helpers/date_helper.rst @@ -0,0 +1,47 @@ +########### +Date Helper +########### + +The Date Helper file contains functions that assist in working with +dates. + +.. contents:: + :local: + +.. raw:: html + +
+ +Loading this Helper +=================== + +This helper is loaded using the following code:: + + helper('date'); + +Available Functions +=================== + +The following functions are available: + +.. php:function:: now([$timezone = NULL]) + + :param string $timezone: Timezone + :returns: UNIX timestamp + :rtype: int + + Returns the current time as a UNIX timestamp, referenced either to your server's + local time or any PHP supported timezone, based on the "time reference" setting + in your config file. If you do not intend to set your master time reference to + any other PHP supported timezone (which you'll typically do if you run a site + that lets each user set their own timezone settings) there is no benefit to using + this function over PHP's ``time()`` function. + :: + + echo now('Australia/Victoria'); + + If a timezone is not provided, it will return ``time()`` based on the + **time_reference** setting. + +Many functions previously found in the CodeIgniter 3 ``date_helper`` have been moved to the ``I18n`` +module in CodeIgniter 4. From 0aef5c083d5d80371a6a415d8e86b5c2a8d1de32 Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Mon, 11 Jun 2018 23:30:14 -0700 Subject: [PATCH 2/4] Date & filesystem helper tests --- tests/system/Helpers/DateHelperTest.php | 9 +- tests/system/Helpers/FilesystemHelperTest.php | 485 +++++++----------- 2 files changed, 197 insertions(+), 297 deletions(-) diff --git a/tests/system/Helpers/DateHelperTest.php b/tests/system/Helpers/DateHelperTest.php index b718ec2fd4e4..bb6bea584b56 100644 --- a/tests/system/Helpers/DateHelperTest.php +++ b/tests/system/Helpers/DateHelperTest.php @@ -23,7 +23,7 @@ public function setUp() public function testNowDefault() { $time = new \DateTime(); - $this->assertLessThan(1, abs(now() - time())); + $this->assertLessThan(1, abs(now() - time())); // close enough } //-------------------------------------------------------------------- @@ -32,13 +32,6 @@ public function testNowSpecific() { // Chicago should be two hours ahead of Vancouver $this->assertEquals(7200,now('America/Chicago')-now('America/Vancouver')); -// $zone = 'America/Vancouver'; -// $time = new \DateTime('now', new \DateTimeZone($zone)); -// echo now($zone) . '\n'; -// echo now() . '\n'; -// echo $time->getTimestamp() . '\n'; -// -// $this->assertLessThan(1, abs(now($zone) - $time->getTimestamp())); } } diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index cbf2c437a502..641851650381 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -5,294 +5,201 @@ class FilesystemHelperTest extends \CIUnitTestCase { - public function testDirectoryMapDefaults() - { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile' - ]; - - $root = vfsStream::setup('root', null, $structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'))); - } - - //-------------------------------------------------------------------- - - public function testDirectoryMapShowsHiddenFiles() - { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); - } - - //-------------------------------------------------------------------- - - public function testDirectoryMapLimitsRecursion() - { - $this->assertTrue(function_exists('directory_map')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR, - 'boo' . DIRECTORY_SEPARATOR, - 'AnEmptyFolder' . DIRECTORY_SEPARATOR, - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); - } - - //-------------------------------------------------------------------- - - public function testWriteFileSuccess() - { - $vfs = vfsStream::setup('root'); - - $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); - $this->assertFileExists($vfs->getChild('test.php')->url()); - } - - //-------------------------------------------------------------------- - - public function testDeleteFilesDefaultsToOneLevelDeep() - { - $this->assertTrue(function_exists('delete_files')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - $vfs = vfsStream::setup('root', null, $structure); - - delete_files(vfsStream::url('root')); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertTrue($vfs->hasChild('foo')); - $this->assertTrue($vfs->hasChild('boo')); - $this->assertTrue($vfs->hasChild('AnEmptyFolder')); - } - - //-------------------------------------------------------------------- - - public function testDeleteFilesHandlesRecursion() - { - $this->assertTrue(function_exists('delete_files')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - $vfs = vfsStream::setup('root', null, $structure); - - delete_files(vfsStream::url('root'), true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - } - - //-------------------------------------------------------------------- - - public function testDeleteFilesLeavesHTFiles() - { - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon', - '.htaccess' => 'Deny All', - 'index.html' => 'foo', - 'index.php' => 'blah' - ]; - - $vfs = vfsStream::setup('root', null, $structure); - - delete_files(vfsStream::url('root'), true, true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - $this->assertTrue($vfs->hasChild('.htaccess')); - $this->assertTrue($vfs->hasChild('index.html')); - $this->assertTrue($vfs->hasChild('index.php')); - } - - //-------------------------------------------------------------------- - - public function testGetFilenames() - { - $this->assertTrue(function_exists('delete_files')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - 'foo', - 'boo', - 'AnEmptyFolder', - 'simpleFile' - ]; - - $vfs = vfsStream::setup('root', null, $structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), false)); - } - - //-------------------------------------------------------------------- - - public function testGetFilenamesWithSource() - { - $this->assertTrue(function_exists('delete_files')); - - $structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - DIRECTORY_SEPARATOR . 'foo', - DIRECTORY_SEPARATOR . 'boo', - DIRECTORY_SEPARATOR . 'AnEmptyFolder', - DIRECTORY_SEPARATOR . 'simpleFile' - ]; - - $vfs = vfsStream::setup('root', null, $structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), true)); - } - - //-------------------------------------------------------------------- - + public function setUp() + { + parent::setUp(); + + $this->structure = [ + 'foo' => [ + 'bar' => 'Once upon a midnight dreary', + 'baz' => 'While I pondered weak and weary' + ], + 'boo' => [ + 'far' => 'Upon a tome of long-forgotten lore', + 'faz' => 'There came a tapping up on the door' + ], + 'AnEmptyFolder' => [], + 'simpleFile' => 'A tap-tap-tapping upon my door', + '.hidden' => 'There is no spoon' + ]; + } + + //-------------------------------------------------------------------- + + public function testDirectoryMapDefaults() + { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'))); + } + + public function testDirectoryMapShowsHiddenFiles() + { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); + } + + public function testDirectoryMapLimitsRecursion() + { + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR, + 'boo' . DIRECTORY_SEPARATOR, + 'AnEmptyFolder' . DIRECTORY_SEPARATOR, + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); + } + + //-------------------------------------------------------------------- + + public function testWriteFileSuccess() + { + $vfs = vfsStream::setup('root'); + + $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); + $this->assertFileExists($vfs->getChild('test.php')->url()); + } + + //-------------------------------------------------------------------- + + public function testDeleteFilesDefaultsToOneLevelDeep() + { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root')); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertTrue($vfs->hasChild('foo')); + $this->assertTrue($vfs->hasChild('boo')); + $this->assertTrue($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesHandlesRecursion() + { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root'), true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesLeavesHTFiles() + { + $structure = array_merge($this->structure, [ + '.htaccess' => 'Deny All', + 'index.html' => 'foo', + 'index.php' => 'blah' + ]); + + $vfs = vfsStream::setup('root', null, $structure); + + delete_files(vfsStream::url('root'), true, true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + $this->assertTrue($vfs->hasChild('.htaccess')); + $this->assertTrue($vfs->hasChild('index.html')); + $this->assertTrue($vfs->hasChild('index.php')); + } + + //-------------------------------------------------------------------- + + public function testGetFilenames() + { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + 'foo', + 'boo', + 'AnEmptyFolder', + 'simpleFile' + ]; + + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), false)); + } + + public function testGetFilenamesWithSource() + { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + DIRECTORY_SEPARATOR . 'foo', + DIRECTORY_SEPARATOR . 'boo', + DIRECTORY_SEPARATOR . 'AnEmptyFolder', + DIRECTORY_SEPARATOR . 'simpleFile' + ]; + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), true)); + } + + //-------------------------------------------------------------------- + + public function testGetFileInfo(){ + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), true)); + + } } From eddf9f544b74215b5b6af5d3c0e9ecb5532ed700 Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Mon, 25 Jun 2018 15:59:07 -0700 Subject: [PATCH 3/4] Fixing directory handling inside filesystem_helper --- system/Helpers/filesystem_helper.php | 54 +-- tests/system/Helpers/FilesystemHelperTest.php | 444 ++++++++++-------- 2 files changed, 266 insertions(+), 232 deletions(-) diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 7e7782386c4a..93a5ec705706 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -1,4 +1,5 @@ 0) && is_dir($source_dir . $file)) { $filedata[$file] = directory_map($source_dir . $file, $new_depth, $hidden); - } - else + } else { $filedata[] = $file; } @@ -94,9 +95,10 @@ function directory_map(string $source_dir, int $directory_depth = 0, bool $hidde closedir($fp); return $filedata; + } catch (Exception $fe) + { + return []; } - - return []; } } @@ -180,8 +182,7 @@ function delete_files(string $path, bool $delDir = false, bool $htdocs = false, if (is_dir($path . DIRECTORY_SEPARATOR . $filename) && $filename[0] !== '.') { delete_files($path . DIRECTORY_SEPARATOR . $filename, $delDir, $htdocs, $_level + 1); - } - elseif ($htdocs !== true || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) + } elseif ($htdocs !== true || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) { @unlink($path . DIRECTORY_SEPARATOR . $filename); } @@ -230,8 +231,7 @@ function get_filenames(string $source_dir, bool $include_path = false, bool $rec if (is_dir($source_dir . $file) && $file[0] !== '.') { get_filenames($source_dir . $file . DIRECTORY_SEPARATOR, $include_path, true); - } - elseif ($file[0] !== '.') + } elseif ($file[0] !== '.') { $filedata[] = ($include_path === true) ? $source_dir . $file : $file; } @@ -285,8 +285,7 @@ function get_dir_file_info(string $source_dir, bool $top_level_only = true, bool if (is_dir($source_dir . $file) && $file[0] !== '.' && $top_level_only === false) { get_dir_file_info($source_dir . $file . DIRECTORY_SEPARATOR, $top_level_only, true); - } - elseif ($file[0] !== '.') + } elseif ($file[0] !== '.') { $filedata[$file] = get_file_info($source_dir . $file); $filedata[$file]['relative_path'] = $relative_path; @@ -318,9 +317,9 @@ function get_dir_file_info(string $source_dir, bool $top_level_only = true, bool * @param string $file Path to file * @param mixed $returned_values Array or comma separated string of information returned * - * @return array + * @return array|null */ - function get_file_info(string $file, $returned_values = ['name', 'server_path', 'size', 'date']): array + function get_file_info(string $file, $returned_values = ['name', 'server_path', 'size', 'date']) { if ( ! file_exists($file)) { @@ -334,8 +333,7 @@ function get_file_info(string $file, $returned_values = ['name', 'server_path', foreach ($returned_values as $key) { - switch ($key) - { + switch ($key) { case 'name': $fileinfo['name'] = basename($file); break; @@ -387,32 +385,25 @@ function symbolic_permissions(int $perms): string if (($perms & 0xC000) === 0xC000) { $symbolic = 's'; // Socket - } - elseif (($perms & 0xA000) === 0xA000) + } elseif (($perms & 0xA000) === 0xA000) { $symbolic = 'l'; // Symbolic Link - } - elseif (($perms & 0x8000) === 0x8000) + } elseif (($perms & 0x8000) === 0x8000) { $symbolic = '-'; // Regular - } - elseif (($perms & 0x6000) === 0x6000) + } elseif (($perms & 0x6000) === 0x6000) { $symbolic = 'b'; // Block special - } - elseif (($perms & 0x4000) === 0x4000) + } elseif (($perms & 0x4000) === 0x4000) { $symbolic = 'd'; // Directory - } - elseif (($perms & 0x2000) === 0x2000) + } elseif (($perms & 0x2000) === 0x2000) { $symbolic = 'c'; // Character special - } - elseif (($perms & 0x1000) === 0x1000) + } elseif (($perms & 0x1000) === 0x1000) { $symbolic = 'p'; // FIFO pipe - } - else + } else { $symbolic = 'u'; // Unknown } @@ -483,8 +474,7 @@ function set_realpath(string $path, bool $checkExistance = false): string if (realpath($path) !== false) { $path = realpath($path); - } - elseif ($checkExistance && ! is_dir($path) && ! is_file($path)) + } elseif ($checkExistance && ! is_dir($path) && ! is_file($path)) { throw new InvalidArgumentException('Not a valid path: ' . $path); } diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index 641851650381..4e72410883f9 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -1,205 +1,249 @@ -structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - } - - //-------------------------------------------------------------------- - - public function testDirectoryMapDefaults() - { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'))); - } - - public function testDirectoryMapShowsHiddenFiles() - { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); - } - - public function testDirectoryMapLimitsRecursion() - { - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR, - 'boo' . DIRECTORY_SEPARATOR, - 'AnEmptyFolder' . DIRECTORY_SEPARATOR, - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); - } - - //-------------------------------------------------------------------- - - public function testWriteFileSuccess() - { - $vfs = vfsStream::setup('root'); - - $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); - $this->assertFileExists($vfs->getChild('test.php')->url()); - } - - //-------------------------------------------------------------------- - - public function testDeleteFilesDefaultsToOneLevelDeep() - { - $this->assertTrue(function_exists('delete_files')); - - $vfs = vfsStream::setup('root', null, $this->structure); - - delete_files(vfsStream::url('root')); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertTrue($vfs->hasChild('foo')); - $this->assertTrue($vfs->hasChild('boo')); - $this->assertTrue($vfs->hasChild('AnEmptyFolder')); - } - - public function testDeleteFilesHandlesRecursion() - { - $this->assertTrue(function_exists('delete_files')); - - $vfs = vfsStream::setup('root', null, $this->structure); - - delete_files(vfsStream::url('root'), true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - } - - public function testDeleteFilesLeavesHTFiles() - { - $structure = array_merge($this->structure, [ - '.htaccess' => 'Deny All', - 'index.html' => 'foo', - 'index.php' => 'blah' - ]); - - $vfs = vfsStream::setup('root', null, $structure); - - delete_files(vfsStream::url('root'), true, true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - $this->assertTrue($vfs->hasChild('.htaccess')); - $this->assertTrue($vfs->hasChild('index.html')); - $this->assertTrue($vfs->hasChild('index.php')); - } - - //-------------------------------------------------------------------- - - public function testGetFilenames() - { - $this->assertTrue(function_exists('delete_files')); - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - 'foo', - 'boo', - 'AnEmptyFolder', - 'simpleFile' - ]; - - $vfs = vfsStream::setup('root', null, $this->structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), false)); - } - - public function testGetFilenamesWithSource() - { - $this->assertTrue(function_exists('delete_files')); - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - DIRECTORY_SEPARATOR . 'foo', - DIRECTORY_SEPARATOR . 'boo', - DIRECTORY_SEPARATOR . 'AnEmptyFolder', - DIRECTORY_SEPARATOR . 'simpleFile' - ]; +class FilesystemHelperTest extends \CIUnitTestCase { + + public function setUp() { + parent::setUp(); + + $this->structure = [ + 'foo' => [ + 'bar' => 'Once upon a midnight dreary', + 'baz' => 'While I pondered weak and weary' + ], + 'boo' => [ + 'far' => 'Upon a tome of long-forgotten lore', + 'faz' => 'There came a tapping up on the door' + ], + 'AnEmptyFolder' => [], + 'simpleFile' => 'A tap-tap-tapping upon my door', + '.hidden' => 'There is no spoon' + ]; + } + + //-------------------------------------------------------------------- + + public function testDirectoryMapDefaults() { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'))); + } + + public function testDirectoryMapShowsHiddenFiles() { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); + } + + public function testDirectoryMapLimitsRecursion() { + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR, + 'boo' . DIRECTORY_SEPARATOR, + 'AnEmptyFolder' . DIRECTORY_SEPARATOR, + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); + } + + public function testDirectoryMapHandlesNotfound() { + $this->assertEquals([], directory_map(SUPPORTPATH . 'Files/shaker/')); + } + + //-------------------------------------------------------------------- + + public function testWriteFileSuccess() { + $vfs = vfsStream::setup('root'); + + $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); + $this->assertFileExists($vfs->getChild('test.php')->url()); + } + + //-------------------------------------------------------------------- + + public function testDeleteFilesDefaultsToOneLevelDeep() { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root')); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertTrue($vfs->hasChild('foo')); + $this->assertTrue($vfs->hasChild('boo')); + $this->assertTrue($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesHandlesRecursion() { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root'), true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesLeavesHTFiles() { + $structure = array_merge($this->structure, [ + '.htaccess' => 'Deny All', + 'index.html' => 'foo', + 'index.php' => 'blah' + ]); + + $vfs = vfsStream::setup('root', null, $structure); + + delete_files(vfsStream::url('root'), true, true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + $this->assertTrue($vfs->hasChild('.htaccess')); + $this->assertTrue($vfs->hasChild('index.html')); + $this->assertTrue($vfs->hasChild('index.php')); + } + + //-------------------------------------------------------------------- + + public function testGetFilenames() { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + 'foo', + 'boo', + 'AnEmptyFolder', + 'simpleFile' + ]; + + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), false)); + } + + public function testGetFilenamesWithSource() { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + DIRECTORY_SEPARATOR . 'foo', + DIRECTORY_SEPARATOR . 'boo', + DIRECTORY_SEPARATOR . 'AnEmptyFolder', + DIRECTORY_SEPARATOR . 'simpleFile' + ]; + + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), true)); + } + + //-------------------------------------------------------------------- + + public function testGetDirFileInfo() { + + $expected = [ + 'banana.php' => [ + 'name' => 'banana.php', + 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', + 'size' => 193, + 'date' => 1529305930, + 'relative_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker', + ] + ]; + + + $this->assertEquals($expected, get_dir_file_info(SUPPORTPATH . 'Files/baker')); + } + + public function testGetFileInfo() { + + $expected = [ + 'name' => 'banana.php', + 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', + 'size' => 193, + 'date' => 1529305930, + ]; + + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php')); + } + + public function testGetFileInfoCustom() { + + $expected = [ + 'readable' => true, + 'writable' => true, + 'executable' => false, + ]; + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'readable,writable,executable')); + } + + public function testGetFileInfoPerms() { + + $expected = 0664; + + $stuff = get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'fileperms'); + $this->assertEquals($expected, $stuff['fileperms'] & 0777); + } + + public function testGetFileNotThereInfo() { + + $expected = null; + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/icer')); + } - $vfs = vfsStream::setup('root', null, $this->structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), true)); - } - - //-------------------------------------------------------------------- - - public function testGetFileInfo(){ - $vfs = vfsStream::setup('root', null, $this->structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), true)); - - } } From 3d064c1d1dd9ac73062e4a13178403930720c5f2 Mon Sep 17 00:00:00 2001 From: Master Yoda Date: Tue, 26 Jun 2018 10:27:43 -0700 Subject: [PATCH 4/4] Beef up filesystem helper & testing for it --- system/Helpers/filesystem_helper.php | 150 +++-- tests/system/Helpers/FilesystemHelperTest.php | 572 ++++++++++-------- 2 files changed, 421 insertions(+), 301 deletions(-) diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 93a5ec705706..f947305a10f2 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -87,7 +87,8 @@ function directory_map(string $source_dir, int $directory_depth = 0, bool $hidde if (($directory_depth < 1 || $new_depth > 0) && is_dir($source_dir . $file)) { $filedata[$file] = directory_map($source_dir . $file, $new_depth, $hidden); - } else + } + else { $filedata[] = $file; } @@ -95,7 +96,8 @@ function directory_map(string $source_dir, int $directory_depth = 0, bool $hidde closedir($fp); return $filedata; - } catch (Exception $fe) + } + catch (\Exception $fe) { return []; } @@ -122,25 +124,29 @@ function directory_map(string $source_dir, int $directory_depth = 0, bool $hidde */ function write_file(string $path, string $data, string $mode = 'wb'): bool { - if ( ! $fp = @fopen($path, $mode)) + try { - return false; - } + $fp = fopen($path, $mode); - flock($fp, LOCK_EX); + flock($fp, LOCK_EX); - for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) - { - if (($result = fwrite($fp, substr($data, $written))) === false) + for ($result = $written = 0, $length = strlen($data); $written < $length; $written += $result) { - break; + if (($result = fwrite($fp, substr($data, $written))) === false) + { + break; + } } - } - flock($fp, LOCK_UN); - fclose($fp); + flock($fp, LOCK_UN); + fclose($fp); - return is_int($result); + return is_int($result); + } + catch (\Exception $fe) + { + return false; + } } } @@ -170,28 +176,33 @@ function delete_files(string $path, bool $delDir = false, bool $htdocs = false, // Trim the trailing slash $path = rtrim($path, '/\\'); - if ( ! $current_dir = @opendir($path)) + try { - return false; - } + $current_dir = opendir($path); - while (false !== ($filename = @readdir($current_dir))) - { - if ($filename !== '.' && $filename !== '..') + while (false !== ($filename = @readdir($current_dir))) { - if (is_dir($path . DIRECTORY_SEPARATOR . $filename) && $filename[0] !== '.') - { - delete_files($path . DIRECTORY_SEPARATOR . $filename, $delDir, $htdocs, $_level + 1); - } elseif ($htdocs !== true || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) + if ($filename !== '.' && $filename !== '..') { - @unlink($path . DIRECTORY_SEPARATOR . $filename); + if (is_dir($path . DIRECTORY_SEPARATOR . $filename) && $filename[0] !== '.') + { + delete_files($path . DIRECTORY_SEPARATOR . $filename, $delDir, $htdocs, $_level + 1); + } + elseif ($htdocs !== true || ! preg_match('/^(\.htaccess|index\.(html|htm|php)|web\.config)$/i', $filename)) + { + @unlink($path . DIRECTORY_SEPARATOR . $filename); + } } } - } - closedir($current_dir); + closedir($current_dir); - return ($delDir === true && $_level > 0) ? @rmdir($path) : true; + return ($delDir === true && $_level > 0) ? @rmdir($path) : true; + } + catch (\Exception $fe) + { + return false; + } } } @@ -217,8 +228,9 @@ function get_filenames(string $source_dir, bool $include_path = false, bool $rec { static $filedata = []; - if ($fp = @opendir($source_dir)) + try { + $fp = opendir($source_dir); // reset the array and make sure $source_dir has a trailing slash on the initial call if ($recursion === false) { @@ -231,7 +243,8 @@ function get_filenames(string $source_dir, bool $include_path = false, bool $rec if (is_dir($source_dir . $file) && $file[0] !== '.') { get_filenames($source_dir . $file . DIRECTORY_SEPARATOR, $include_path, true); - } elseif ($file[0] !== '.') + } + elseif ($file[0] !== '.') { $filedata[] = ($include_path === true) ? $source_dir . $file : $file; } @@ -240,8 +253,10 @@ function get_filenames(string $source_dir, bool $include_path = false, bool $rec closedir($fp); return $filedata; } - - return []; + catch (\Exception $fe) + { + return []; + } } } @@ -270,33 +285,38 @@ function get_dir_file_info(string $source_dir, bool $top_level_only = true, bool static $filedata = []; $relative_path = $source_dir; - if ($fp = @opendir($source_dir)) + try { - // reset the array and make sure $source_dir has a trailing slash on the initial call - if ($recursion === false) - { - $filedata = []; - $source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; - } - - // Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast - while (false !== ($file = readdir($fp))) - { - if (is_dir($source_dir . $file) && $file[0] !== '.' && $top_level_only === false) + $fp = @opendir($source_dir); { + // reset the array and make sure $source_dir has a trailing slash on the initial call + if ($recursion === false) { - get_dir_file_info($source_dir . $file . DIRECTORY_SEPARATOR, $top_level_only, true); - } elseif ($file[0] !== '.') + $filedata = []; + $source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + } + + // Used to be foreach (scandir($source_dir, 1) as $file), but scandir() is simply not as fast + while (false !== ($file = readdir($fp))) { - $filedata[$file] = get_file_info($source_dir . $file); - $filedata[$file]['relative_path'] = $relative_path; + if (is_dir($source_dir . $file) && $file[0] !== '.' && $top_level_only === false) + { + get_dir_file_info($source_dir . $file . DIRECTORY_SEPARATOR, $top_level_only, true); + } + elseif ($file[0] !== '.') + { + $filedata[$file] = get_file_info($source_dir . $file); + $filedata[$file]['relative_path'] = $relative_path; + } } - } - closedir($fp); - return $filedata; + closedir($fp); + return $filedata; + } + } + catch (\Exception $fe) + { + return []; } - - return []; } } @@ -385,25 +405,32 @@ function symbolic_permissions(int $perms): string if (($perms & 0xC000) === 0xC000) { $symbolic = 's'; // Socket - } elseif (($perms & 0xA000) === 0xA000) + } + elseif (($perms & 0xA000) === 0xA000) { $symbolic = 'l'; // Symbolic Link - } elseif (($perms & 0x8000) === 0x8000) + } + elseif (($perms & 0x8000) === 0x8000) { $symbolic = '-'; // Regular - } elseif (($perms & 0x6000) === 0x6000) + } + elseif (($perms & 0x6000) === 0x6000) { $symbolic = 'b'; // Block special - } elseif (($perms & 0x4000) === 0x4000) + } + elseif (($perms & 0x4000) === 0x4000) { $symbolic = 'd'; // Directory - } elseif (($perms & 0x2000) === 0x2000) + } + elseif (($perms & 0x2000) === 0x2000) { $symbolic = 'c'; // Character special - } elseif (($perms & 0x1000) === 0x1000) + } + elseif (($perms & 0x1000) === 0x1000) { $symbolic = 'p'; // FIFO pipe - } else + } + else { $symbolic = 'u'; // Unknown } @@ -474,7 +501,8 @@ function set_realpath(string $path, bool $checkExistance = false): string if (realpath($path) !== false) { $path = realpath($path); - } elseif ($checkExistance && ! is_dir($path) && ! is_file($path)) + } + elseif ($checkExistance && ! is_dir($path) && ! is_file($path)) { throw new InvalidArgumentException('Not a valid path: ' . $path); } diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index 4e72410883f9..5df5deca00a7 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -4,246 +4,338 @@ use org\bovigo\vfs\vfsStream; -class FilesystemHelperTest extends \CIUnitTestCase { - - public function setUp() { - parent::setUp(); - - $this->structure = [ - 'foo' => [ - 'bar' => 'Once upon a midnight dreary', - 'baz' => 'While I pondered weak and weary' - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door' - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon' - ]; - } - - //-------------------------------------------------------------------- - - public function testDirectoryMapDefaults() { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'))); - } - - public function testDirectoryMapShowsHiddenFiles() { - helper('filesystem'); - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR => [ - 'bar', - 'baz' - ], - 'boo' . DIRECTORY_SEPARATOR => [ - 'far', - 'faz' - ], - 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); - } - - public function testDirectoryMapLimitsRecursion() { - $this->assertTrue(function_exists('directory_map')); - - $expected = [ - 'foo' . DIRECTORY_SEPARATOR, - 'boo' . DIRECTORY_SEPARATOR, - 'AnEmptyFolder' . DIRECTORY_SEPARATOR, - 'simpleFile', - '.hidden' - ]; - - $root = vfsStream::setup('root', null, $this->structure); - $this->assertTrue($root->hasChild('foo')); - - $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); - } - - public function testDirectoryMapHandlesNotfound() { - $this->assertEquals([], directory_map(SUPPORTPATH . 'Files/shaker/')); - } - - //-------------------------------------------------------------------- - - public function testWriteFileSuccess() { - $vfs = vfsStream::setup('root'); - - $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); - $this->assertFileExists($vfs->getChild('test.php')->url()); - } - - //-------------------------------------------------------------------- - - public function testDeleteFilesDefaultsToOneLevelDeep() { - $this->assertTrue(function_exists('delete_files')); - - $vfs = vfsStream::setup('root', null, $this->structure); - - delete_files(vfsStream::url('root')); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertTrue($vfs->hasChild('foo')); - $this->assertTrue($vfs->hasChild('boo')); - $this->assertTrue($vfs->hasChild('AnEmptyFolder')); - } - - public function testDeleteFilesHandlesRecursion() { - $this->assertTrue(function_exists('delete_files')); +class FilesystemHelperTest extends \CIUnitTestCase +{ + + public function setUp() + { + parent::setUp(); + + $this->structure = [ + 'foo' => [ + 'bar' => 'Once upon a midnight dreary', + 'baz' => 'While I pondered weak and weary' + ], + 'boo' => [ + 'far' => 'Upon a tome of long-forgotten lore', + 'faz' => 'There came a tapping up on the door' + ], + 'AnEmptyFolder' => [], + 'simpleFile' => 'A tap-tap-tapping upon my door', + '.hidden' => 'There is no spoon' + ]; + } + + //-------------------------------------------------------------------- + + public function testDirectoryMapDefaults() + { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'))); + } + + public function testDirectoryMapShowsHiddenFiles() + { + helper('filesystem'); + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR => [ + 'bar', + 'baz' + ], + 'boo' . DIRECTORY_SEPARATOR => [ + 'far', + 'faz' + ], + 'AnEmptyFolder' . DIRECTORY_SEPARATOR => [], + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), false, true)); + } + + public function testDirectoryMapLimitsRecursion() + { + $this->assertTrue(function_exists('directory_map')); + + $expected = [ + 'foo' . DIRECTORY_SEPARATOR, + 'boo' . DIRECTORY_SEPARATOR, + 'AnEmptyFolder' . DIRECTORY_SEPARATOR, + 'simpleFile', + '.hidden' + ]; + + $root = vfsStream::setup('root', null, $this->structure); + $this->assertTrue($root->hasChild('foo')); + + $this->assertEquals($expected, directory_map(vfsStream::url('root'), 1, true)); + } + + public function testDirectoryMapHandlesNotfound() + { + $this->assertEquals([], directory_map(SUPPORTPATH . 'Files/shaker/')); + } + + //-------------------------------------------------------------------- + + public function testWriteFileSuccess() + { + $vfs = vfsStream::setup('root'); + + $this->assertTrue(write_file(vfsStream::url('root/test.php'), 'Simple')); + $this->assertFileExists($vfs->getChild('test.php')->url()); + } + + public function testWriteFileFailure() + { + $vfs = vfsStream::setup('root'); + + $this->assertFalse(write_file(vfsStream::url('apple#test.php'), 'Simple')); + } + + //-------------------------------------------------------------------- + + public function testDeleteFilesDefaultsToOneLevelDeep() + { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root')); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertTrue($vfs->hasChild('foo')); + $this->assertTrue($vfs->hasChild('boo')); + $this->assertTrue($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesHandlesRecursion() + { + $this->assertTrue(function_exists('delete_files')); + + $vfs = vfsStream::setup('root', null, $this->structure); + + delete_files(vfsStream::url('root'), true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('.hidden')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + } + + public function testDeleteFilesLeavesHTFiles() + { + $structure = array_merge($this->structure, [ + '.htaccess' => 'Deny All', + 'index.html' => 'foo', + 'index.php' => 'blah' + ]); + + $vfs = vfsStream::setup('root', null, $structure); + + delete_files(vfsStream::url('root'), true, true); + + $this->assertFalse($vfs->hasChild('simpleFile')); + $this->assertFalse($vfs->hasChild('foo')); + $this->assertFalse($vfs->hasChild('boo')); + $this->assertFalse($vfs->hasChild('AnEmptyFolder')); + $this->assertTrue($vfs->hasChild('.htaccess')); + $this->assertTrue($vfs->hasChild('index.html')); + $this->assertTrue($vfs->hasChild('index.php')); + } + + public function testDeleteFilesFailure() + { + $this->assertFalse(delete_files(SUPPORTPATH . 'Files/shaker/')); + } + + //-------------------------------------------------------------------- + + public function testGetFilenames() + { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + 'foo', + 'boo', + 'AnEmptyFolder', + 'simpleFile' + ]; + + $vfs = vfsStream::setup('root', null, $this->structure); - $vfs = vfsStream::setup('root', null, $this->structure); - - delete_files(vfsStream::url('root'), true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('.hidden')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - } - - public function testDeleteFilesLeavesHTFiles() { - $structure = array_merge($this->structure, [ - '.htaccess' => 'Deny All', - 'index.html' => 'foo', - 'index.php' => 'blah' - ]); - - $vfs = vfsStream::setup('root', null, $structure); - - delete_files(vfsStream::url('root'), true, true); - - $this->assertFalse($vfs->hasChild('simpleFile')); - $this->assertFalse($vfs->hasChild('foo')); - $this->assertFalse($vfs->hasChild('boo')); - $this->assertFalse($vfs->hasChild('AnEmptyFolder')); - $this->assertTrue($vfs->hasChild('.htaccess')); - $this->assertTrue($vfs->hasChild('index.html')); - $this->assertTrue($vfs->hasChild('index.php')); - } - - //-------------------------------------------------------------------- - - public function testGetFilenames() { - $this->assertTrue(function_exists('delete_files')); - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - 'foo', - 'boo', - 'AnEmptyFolder', - 'simpleFile' - ]; - - $vfs = vfsStream::setup('root', null, $this->structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), false)); - } - - public function testGetFilenamesWithSource() { - $this->assertTrue(function_exists('delete_files')); - - // Not sure the directory names should actually show up - // here but this matches v3.x results. - $expected = [ - DIRECTORY_SEPARATOR . 'foo', - DIRECTORY_SEPARATOR . 'boo', - DIRECTORY_SEPARATOR . 'AnEmptyFolder', - DIRECTORY_SEPARATOR . 'simpleFile' - ]; - - $vfs = vfsStream::setup('root', null, $this->structure); - - $this->assertEquals($expected, get_filenames($vfs->url(), true)); - } - - //-------------------------------------------------------------------- - - public function testGetDirFileInfo() { - - $expected = [ - 'banana.php' => [ - 'name' => 'banana.php', - 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', - 'size' => 193, - 'date' => 1529305930, - 'relative_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker', - ] - ]; - - - $this->assertEquals($expected, get_dir_file_info(SUPPORTPATH . 'Files/baker')); - } - - public function testGetFileInfo() { - - $expected = [ - 'name' => 'banana.php', - 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', - 'size' => 193, - 'date' => 1529305930, - ]; - - - $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php')); - } - - public function testGetFileInfoCustom() { - - $expected = [ - 'readable' => true, - 'writable' => true, - 'executable' => false, - ]; - - $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'readable,writable,executable')); - } - - public function testGetFileInfoPerms() { - - $expected = 0664; - - $stuff = get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'fileperms'); - $this->assertEquals($expected, $stuff['fileperms'] & 0777); - } - - public function testGetFileNotThereInfo() { - - $expected = null; - - $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/icer')); - } + $this->assertEquals($expected, get_filenames($vfs->url(), false)); + } + + public function testGetFilenamesWithSource() + { + $this->assertTrue(function_exists('delete_files')); + + // Not sure the directory names should actually show up + // here but this matches v3.x results. + $expected = [ + DIRECTORY_SEPARATOR . 'foo', + DIRECTORY_SEPARATOR . 'boo', + DIRECTORY_SEPARATOR . 'AnEmptyFolder', + DIRECTORY_SEPARATOR . 'simpleFile' + ]; + + $vfs = vfsStream::setup('root', null, $this->structure); + + $this->assertEquals($expected, get_filenames($vfs->url(), true)); + } + + public function testGetFilenamesFailure() + { + $this->assertEquals([], get_filenames(SUPPORTPATH . 'Files/shaker/')); + } + + //-------------------------------------------------------------------- + + public function testGetDirFileInfo() + { + $expected = [ + 'banana.php' => [ + 'name' => 'banana.php', + 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', + 'size' => 193, + 'date' => 1529305930, + 'relative_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker', + ] + ]; + + + $this->assertEquals($expected, get_dir_file_info(SUPPORTPATH . 'Files/baker')); + } + + public function testGetDirFileInfoNested() + { + $expected = ['banana.php', 'prune_ripe.php', 'fig_3.php', 'apple.php']; + + $results = get_dir_file_info(SUPPORTPATH . 'Files', false); + $this->assertEmpty(array_diff($expected, array_keys($results))); + } + + public function testGetDirFileInfoFailure() + { + $expected = []; + + $this->assertEquals($expected, get_dir_file_info(SUPPORTPATH . 'Files#baker')); + } + + //-------------------------------------------------------------------- + + public function testGetFileInfo() + { + $expected = [ + 'name' => 'banana.php', + 'server_path' => '/pub7/htdocs/CodeIgniter4/tests/_support/Files/baker/banana.php', + 'size' => 193, + 'date' => 1529305930, + ]; + + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php')); + } + + public function testGetFileInfoCustom() + { + $expected = [ + 'readable' => true, + 'writable' => true, + 'executable' => false, + ]; + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'readable,writable,executable')); + } + + public function testGetFileInfoPerms() + { + $expected = 0664; + + $stuff = get_file_info(SUPPORTPATH . 'Files/baker/banana.php', 'fileperms'); + $this->assertEquals($expected, $stuff['fileperms'] & 0777); + } + + public function testGetFileNotThereInfo() + { + $expected = null; + + $this->assertEquals($expected, get_file_info(SUPPORTPATH . 'Files/icer')); + } + + //-------------------------------------------------------------------- + public function testOctalPermissions() + { + $this->assertEquals('777', octal_permissions(0777)); + $this->assertEquals('655', octal_permissions(0655)); + $this->assertEquals('123', octal_permissions(0123)); + } + + public function testSymbolicPermissions() + { + $expected = [ + 0777 => 'urwxrwxrwx', + 0655 => 'urw-r-xr-x', + 0123 => 'u--x-w--wx', + 010655 => 'prw-r-xr-x', + 020655 => 'crw-r-xr-x', + 040655 => 'drw-r-xr-x', + 060655 => 'brw-r-xr-x', + 0100655 => '-rw-r-xr-x', + 0120655 => 'lrw-r-xr-x', + 0140655 => 'srw-r-xr-x', + ]; + + foreach ($expected as $perm => $value) + $this->assertEquals($value, symbolic_permissions($perm)); + } + + //-------------------------------------------------------------------- + + public function testRealPathURL() + { + $this->expectException(\InvalidArgumentException::class); + set_realpath('http://somewhere.com/overtherainbow'); + } + + public function testRealPathInvalid() + { + $this->expectException(\InvalidArgumentException::class); + set_realpath(SUPPORTPATH . 'root/../', true); + } + + public function testRealPathResolved() + { + $this->assertEquals(SUPPORTPATH . 'Helpers/', set_realpath(SUPPORTPATH . 'Files/../Helpers', true)); + } }