You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1218 lines
41 KiB
1218 lines
41 KiB
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* Unit tests for file_system.
|
|
*
|
|
* @package core_files
|
|
* @category phpunit
|
|
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
global $CFG;
|
|
require_once($CFG->libdir . '/filestorage/file_system.php');
|
|
|
|
/**
|
|
* Unit tests for file_system.
|
|
*
|
|
* @package core_files
|
|
* @category phpunit
|
|
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
* @coversDefaultClass file_system
|
|
*/
|
|
class core_files_file_system_testcase extends advanced_testcase {
|
|
|
|
public function setUp() {
|
|
get_file_storage(true);
|
|
}
|
|
|
|
public function tearDown() {
|
|
get_file_storage(true);
|
|
}
|
|
|
|
/**
|
|
* Helper function to help setup and configure the virtual file system stream.
|
|
*
|
|
* @param array $filedir Directory structure and content of the filedir
|
|
* @param array $trashdir Directory structure and content of the sourcedir
|
|
* @param array $sourcedir Directory structure and content of a directory used for source files for tests
|
|
* @return \org\bovigo\vfs\vfsStream
|
|
*/
|
|
protected function setup_vfile_root($content = []) {
|
|
$vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, $content);
|
|
|
|
return $vfileroot;
|
|
}
|
|
|
|
/**
|
|
* Helper to create a stored file objectw with the given supplied content.
|
|
*
|
|
* @param string $filecontent The content of the mocked file
|
|
* @param string $filename The file name to use in the stored_file
|
|
* @param array $mockedmethods A list of methods you intend to override
|
|
* If no methods are specified, only abstract functions are mocked.
|
|
* @return stored_file
|
|
*/
|
|
protected function get_stored_file($filecontent, $filename = null, $mockedmethods = null) {
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
if (empty($filename)) {
|
|
$filename = $contenthash;
|
|
}
|
|
|
|
$file = $this->getMockBuilder(stored_file::class)
|
|
->setMethods($mockedmethods)
|
|
->setConstructorArgs([
|
|
get_file_storage(),
|
|
(object) [
|
|
'contenthash' => $contenthash,
|
|
'filesize' => strlen($filecontent),
|
|
'filename' => $filename,
|
|
]
|
|
])
|
|
->getMock();
|
|
|
|
return $file;
|
|
}
|
|
|
|
/**
|
|
* Get a testable mock of the abstract file_system class.
|
|
*
|
|
* @param array $mockedmethods A list of methods you intend to override
|
|
* If no methods are specified, only abstract functions are mocked.
|
|
* @return file_system
|
|
*/
|
|
protected function get_testable_mock($mockedmethods = []) {
|
|
$fs = $this->getMockBuilder(file_system::class)
|
|
->setMethods($mockedmethods)
|
|
->getMockForAbstractClass();
|
|
|
|
return $fs;
|
|
}
|
|
|
|
/**
|
|
* Ensure that the file system is not clonable.
|
|
*
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_not_cloneable() {
|
|
$reflection = new ReflectionClass('file_system');
|
|
$this->assertFalse($reflection->isCloneable());
|
|
}
|
|
|
|
/**
|
|
* Ensure that the filedir file_system extension is used by default.
|
|
*
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_default_class() {
|
|
$this->resetAfterTest();
|
|
|
|
// Ensure that the alternative_file_system_class is null.
|
|
global $CFG;
|
|
$CFG->alternative_file_system_class = null;
|
|
|
|
$storage = get_file_storage();
|
|
$fs = $storage->get_file_system();
|
|
$this->assertInstanceOf(file_system::class, $fs);
|
|
$this->assertEquals(file_system_filedir::class, get_class($fs));
|
|
}
|
|
|
|
/**
|
|
* Ensure that the specified file_system extension class is used.
|
|
*
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_supplied_class() {
|
|
global $CFG;
|
|
$this->resetAfterTest();
|
|
|
|
// Mock the file_system.
|
|
// Mocks create a new child of the mocked class which is perfect for this test.
|
|
$filesystem = $this->getMockBuilder('file_system')
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
$CFG->alternative_file_system_class = get_class($filesystem);
|
|
|
|
$storage = get_file_storage();
|
|
$fs = $storage->get_file_system();
|
|
$this->assertInstanceOf(file_system::class, $fs);
|
|
$this->assertEquals(get_class($filesystem), get_class($fs));
|
|
}
|
|
|
|
/**
|
|
* Test that the readfile function outputs content to disk.
|
|
*
|
|
* @covers ::readfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_readfile_remote() {
|
|
global $CFG;
|
|
|
|
// Mock the filesystem.
|
|
$filecontent = 'example content';
|
|
$vfileroot = $this->setup_vfile_root(['sourcefile' => $filecontent]);
|
|
$filepath = \org\bovigo\vfs\vfsStream::url('root/sourcefile');
|
|
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
// Mock the file_system class.
|
|
// We need to override the get_remote_path_from_storedfile function.
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_storedfile',
|
|
'is_file_readable_locally_by_storedfile',
|
|
'get_local_path_from_storedfile',
|
|
]);
|
|
$fs->method('get_remote_path_from_storedfile')->willReturn($filepath);
|
|
$fs->method('is_file_readable_locally_by_storedfile')->willReturn(false);
|
|
$fs->expects($this->never())->method('get_local_path_from_storedfile');
|
|
|
|
// Note: It is currently not possible to mock readfile_allow_large
|
|
// because file_system is in the global namespace.
|
|
// We must therefore check for expected output. This is not ideal.
|
|
$this->expectOutputString($filecontent);
|
|
$fs->readfile($file);
|
|
}
|
|
|
|
/**
|
|
* Test that the readfile function outputs content to disk.
|
|
*
|
|
* @covers ::readfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_readfile_local() {
|
|
global $CFG;
|
|
|
|
// Mock the filesystem.
|
|
$filecontent = 'example content';
|
|
$vfileroot = $this->setup_vfile_root(['sourcefile' => $filecontent]);
|
|
$filepath = \org\bovigo\vfs\vfsStream::url('root/sourcefile');
|
|
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
// Mock the file_system class.
|
|
// We need to override the get_remote_path_from_storedfile function.
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_storedfile',
|
|
'is_file_readable_locally_by_storedfile',
|
|
'get_local_path_from_storedfile',
|
|
]);
|
|
$fs->method('is_file_readable_locally_by_storedfile')->willReturn(true);
|
|
$fs->expects($this->never())->method('get_remote_path_from_storedfile');
|
|
$fs->expects($this->once())->method('get_local_path_from_storedfile')->willReturn($filepath);
|
|
|
|
// Note: It is currently not possible to mock readfile_allow_large
|
|
// because file_system is in the global namespace.
|
|
// We must therefore check for expected output. This is not ideal.
|
|
$this->expectOutputString($filecontent);
|
|
$fs->readfile($file);
|
|
}
|
|
|
|
/**
|
|
* Test that the get_local_path_from_storedfile function functions
|
|
* correctly when called with various args.
|
|
*
|
|
* @dataProvider get_local_path_from_storedfile_provider
|
|
* @param array $args The additional args to pass to get_local_path_from_storedfile
|
|
* @param bool $fetch Whether the combination of args should have caused a fetch
|
|
*
|
|
* @covers ::get_local_path_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_local_path_from_storedfile($args, $fetch) {
|
|
$filepath = '/path/to/file';
|
|
$filecontent = 'example content';
|
|
|
|
// Get the filesystem mock.
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_hash',
|
|
]);
|
|
$fs->expects($this->once())
|
|
->method('get_local_path_from_hash')
|
|
->with($this->equalTo(file_storage::hash_from_string($filecontent)), $this->equalTo($fetch))
|
|
->willReturn($filepath);
|
|
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'get_local_path_from_storedfile');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs($fs, array_merge([$file], $args));
|
|
|
|
$this->assertEquals($filepath, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the default implementation of get_remote_path_from_storedfile
|
|
* simply calls get_local_path_from_storedfile without requiring a
|
|
* fetch.
|
|
*
|
|
* @covers ::get_remote_path_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_remote_path_from_storedfile() {
|
|
$filepath = '/path/to/file';
|
|
$filecontent = 'example content';
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_hash',
|
|
]);
|
|
|
|
$fs->expects($this->once())
|
|
->method('get_remote_path_from_hash')
|
|
->with($this->equalTo(file_storage::hash_from_string($filecontent)), $this->equalTo(false))
|
|
->willReturn($filepath);
|
|
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'get_remote_path_from_storedfile');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs($fs, [$file]);
|
|
|
|
$this->assertEquals($filepath, $result);
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_locally_by_hash with a valid file.
|
|
*
|
|
* This should call get_local_path_from_hash and check the readability
|
|
* of the file.
|
|
*
|
|
* Fetching the file is optional.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_locally_by_hash() {
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
$filepath = __FILE__;
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_hash',
|
|
]);
|
|
|
|
$fs->method('get_local_path_from_hash')
|
|
->with($this->equalTo($contenthash), $this->equalTo(false))
|
|
->willReturn($filepath);
|
|
|
|
$this->assertTrue($fs->is_file_readable_locally_by_hash($contenthash));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_locally_by_hash with an empty file.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_locally_by_hash_empty() {
|
|
$filecontent = '';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_hash',
|
|
]);
|
|
|
|
$fs->expects($this->never())
|
|
->method('get_local_path_from_hash');
|
|
|
|
$this->assertTrue($fs->is_file_readable_locally_by_hash($contenthash));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_remotely_by_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_hash() {
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_hash',
|
|
]);
|
|
|
|
$fs->method('get_remote_path_from_hash')
|
|
->with($this->equalTo($contenthash), $this->equalTo(false))
|
|
->willReturn(__FILE__);
|
|
|
|
$this->assertTrue($fs->is_file_readable_remotely_by_hash($contenthash));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_remotely_by_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_hash_empty() {
|
|
$filecontent = '';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_hash',
|
|
]);
|
|
|
|
$fs->expects($this->never())
|
|
->method('get_remote_path_from_hash');
|
|
|
|
$this->assertTrue($fs->is_file_readable_remotely_by_hash($contenthash));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_remotely_by_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_hash_not_found() {
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_hash',
|
|
]);
|
|
|
|
$fs->method('get_remote_path_from_hash')
|
|
->with($this->equalTo($contenthash), $this->equalTo(false))
|
|
->willReturn('/path/to/nonexistent/file');
|
|
|
|
$this->assertFalse($fs->is_file_readable_remotely_by_hash($contenthash));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_remotely_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_storedfile() {
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_storedfile',
|
|
]);
|
|
|
|
$fs->method('get_remote_path_from_storedfile')
|
|
->willReturn(__FILE__);
|
|
|
|
$this->assertTrue($fs->is_file_readable_remotely_by_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_remotely_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_storedfile_empty() {
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_storedfile',
|
|
]);
|
|
|
|
$fs->expects($this->never())
|
|
->method('get_remote_path_from_storedfile');
|
|
|
|
$file = $this->get_stored_file('');
|
|
$this->assertTrue($fs->is_file_readable_remotely_by_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_locally_by_storedfile with an empty file.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_locally_by_storedfile_empty() {
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_storedfile',
|
|
]);
|
|
|
|
$fs->expects($this->never())
|
|
->method('get_local_path_from_storedfile');
|
|
|
|
$file = $this->get_stored_file('');
|
|
$this->assertTrue($fs->is_file_readable_locally_by_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_remotely_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_remotely_by_storedfile_not_found() {
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_storedfile',
|
|
]);
|
|
|
|
$fs->method('get_remote_path_from_storedfile')
|
|
->willReturn(__LINE__);
|
|
|
|
$this->assertFalse($fs->is_file_readable_remotely_by_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_locally_by_storedfile with a valid file.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_locally_by_storedfile_unreadable() {
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_storedfile',
|
|
]);
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(false))
|
|
->willReturn('/path/to/nonexistent/file');
|
|
|
|
$this->assertFalse($fs->is_file_readable_locally_by_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of is_file_readable_locally_by_storedfile with a valid file should pass fetch.
|
|
*
|
|
* @covers ::is_file_readable_locally_by_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_readable_locally_by_storedfile_passes_fetch() {
|
|
$fs = $this->get_testable_mock([
|
|
'get_local_path_from_storedfile',
|
|
]);
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn('/path/to/nonexistent/file');
|
|
|
|
$this->assertFalse($fs->is_file_readable_locally_by_storedfile($file, true));
|
|
}
|
|
|
|
/**
|
|
* Ensure that is_file_removable returns correctly for an empty file.
|
|
*
|
|
* @covers ::is_file_removable
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_removable_empty() {
|
|
$filecontent = '';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'is_file_removable');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs(null, [$contenthash]);
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that is_file_removable returns false if the file is still in use.
|
|
*
|
|
* @covers ::is_file_removable
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_removable_in_use() {
|
|
$this->resetAfterTest();
|
|
global $DB;
|
|
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$DB = $this->getMockBuilder(\moodle_database::class)
|
|
->setMethods(['record_exists'])
|
|
->getMockForAbstractClass();
|
|
$DB->method('record_exists')->willReturn(true);
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'is_file_removable');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs(null, [$contenthash]);
|
|
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that is_file_removable returns false if the file is not in use.
|
|
*
|
|
* @covers ::is_file_removable
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_file_removable_not_in_use() {
|
|
$this->resetAfterTest();
|
|
global $DB;
|
|
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$DB = $this->getMockBuilder(\moodle_database::class)
|
|
->setMethods(['record_exists'])
|
|
->getMockForAbstractClass();
|
|
$DB->method('record_exists')->willReturn(false);
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'is_file_removable');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs(null, [$contenthash]);
|
|
|
|
$this->assertTrue($result);
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of get_content.
|
|
*
|
|
* @covers ::get_content
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_content() {
|
|
global $CFG;
|
|
|
|
// Mock the filesystem.
|
|
$filecontent = 'example content';
|
|
$vfileroot = $this->setup_vfile_root(['sourcefile' => $filecontent]);
|
|
$filepath = \org\bovigo\vfs\vfsStream::url('root/sourcefile');
|
|
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
// Mock the file_system class.
|
|
// We need to override the get_remote_path_from_storedfile function.
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
|
$fs->method('get_remote_path_from_storedfile')->willReturn($filepath);
|
|
|
|
$result = $fs->get_content($file);
|
|
|
|
$this->assertEquals($filecontent, $result);
|
|
}
|
|
|
|
/**
|
|
* Test the stock implementation of get_content.
|
|
*
|
|
* @covers ::get_content
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_content_empty() {
|
|
global $CFG;
|
|
|
|
$filecontent = '';
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
// Mock the file_system class.
|
|
// We need to override the get_remote_path_from_storedfile function.
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
|
$fs->expects($this->never())
|
|
->method('get_remote_path_from_storedfile');
|
|
|
|
$result = $fs->get_content($file);
|
|
|
|
$this->assertEquals($filecontent, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the list_files function requires a local copy of the
|
|
* file, and passes the path to the packer.
|
|
*
|
|
* @covers ::list_files
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_list_files() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
$filepath = __FILE__;
|
|
$expectedresult = (object) [];
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn(__FILE__);
|
|
|
|
$packer = $this->getMockBuilder(file_packer::class)
|
|
->setMethods(['list_files'])
|
|
->getMockForAbstractClass();
|
|
|
|
$packer->expects($this->once())
|
|
->method('list_files')
|
|
->with($this->equalTo($filepath))
|
|
->willReturn($expectedresult);
|
|
|
|
$result = $fs->list_files($file, $packer);
|
|
|
|
$this->assertEquals($expectedresult, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the extract_to_pathname function requires a local copy of the
|
|
* file, and passes the path to the packer.
|
|
*
|
|
* @covers ::extract_to_pathname
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_extract_to_pathname() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
$filepath = __FILE__;
|
|
$expectedresult = (object) [];
|
|
$outputpath = '/path/to/output';
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn(__FILE__);
|
|
|
|
$packer = $this->getMockBuilder(file_packer::class)
|
|
->setMethods(['extract_to_pathname'])
|
|
->getMockForAbstractClass();
|
|
|
|
$packer->expects($this->once())
|
|
->method('extract_to_pathname')
|
|
->with($this->equalTo($filepath), $this->equalTo($outputpath), $this->equalTo(null), $this->equalTo(null))
|
|
->willReturn($expectedresult);
|
|
|
|
$result = $fs->extract_to_pathname($file, $packer, $outputpath);
|
|
|
|
$this->assertEquals($expectedresult, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the extract_to_storage function requires a local copy of the
|
|
* file, and passes the path to the packer.
|
|
*
|
|
* @covers ::extract_to_storage
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_extract_to_storage() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
$filepath = __FILE__;
|
|
$expectedresult = (object) [];
|
|
$outputpath = '/path/to/output';
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn(__FILE__);
|
|
|
|
$packer = $this->getMockBuilder(file_packer::class)
|
|
->setMethods(['extract_to_storage'])
|
|
->getMockForAbstractClass();
|
|
|
|
$packer->expects($this->once())
|
|
->method('extract_to_storage')
|
|
->with(
|
|
$this->equalTo($filepath),
|
|
$this->equalTo(42),
|
|
$this->equalTo('component'),
|
|
$this->equalTo('filearea'),
|
|
$this->equalTo('itemid'),
|
|
$this->equalTo('pathbase'),
|
|
$this->equalTo('userid'),
|
|
$this->equalTo(null)
|
|
)
|
|
->willReturn($expectedresult);
|
|
|
|
$result = $fs->extract_to_storage($file, $packer, 42, 'component','filearea', 'itemid', 'pathbase', 'userid');
|
|
|
|
$this->assertEquals($expectedresult, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the add_storedfile_to_archive function requires a local copy of the
|
|
* file, and passes the path to the archive.
|
|
*
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_add_storedfile_to_archive_directory() {
|
|
$file = $this->get_stored_file('', '.');
|
|
$archivepath = 'example';
|
|
$expectedresult = (object) [];
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn(__FILE__);
|
|
|
|
$archive = $this->getMockBuilder(file_archive::class)
|
|
->setMethods([
|
|
'add_directory',
|
|
'add_file_from_pathname',
|
|
])
|
|
->getMockForAbstractClass();
|
|
|
|
$archive->expects($this->once())
|
|
->method('add_directory')
|
|
->with($this->equalTo($archivepath))
|
|
->willReturn($expectedresult);
|
|
|
|
$archive->expects($this->never())
|
|
->method('add_file_from_pathname');
|
|
|
|
$result = $fs->add_storedfile_to_archive($file, $archive, $archivepath);
|
|
|
|
$this->assertEquals($expectedresult, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the add_storedfile_to_archive function requires a local copy of the
|
|
* file, and passes the path to the archive.
|
|
*
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_add_storedfile_to_archive_file() {
|
|
$file = $this->get_stored_file('example content');
|
|
$filepath = __LINE__;
|
|
$archivepath = 'example';
|
|
$expectedresult = (object) [];
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn($filepath);
|
|
|
|
$archive = $this->getMockBuilder(file_archive::class)
|
|
->setMethods([
|
|
'add_directory',
|
|
'add_file_from_pathname',
|
|
])
|
|
->getMockForAbstractClass();
|
|
|
|
$archive->expects($this->never())
|
|
->method('add_directory');
|
|
|
|
$archive->expects($this->once())
|
|
->method('add_file_from_pathname')
|
|
->with(
|
|
$this->equalTo($archivepath),
|
|
$this->equalTo($filepath)
|
|
)
|
|
->willReturn($expectedresult);
|
|
|
|
$result = $fs->add_storedfile_to_archive($file, $archive, $archivepath);
|
|
|
|
$this->assertEquals($expectedresult, $result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that the add_to_curl_request function requires a local copy of the
|
|
* file, and passes the path to curl_file_create.
|
|
*
|
|
* @covers ::add_to_curl_request
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_add_to_curl_request() {
|
|
$file = $this->get_stored_file('example content');
|
|
$filepath = __FILE__;
|
|
$archivepath = 'example';
|
|
$key = 'myfile';
|
|
|
|
// Mock the file_system class.
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn($filepath);
|
|
|
|
$request = (object) ['_tmp_file_post_params' => []];
|
|
$fs->add_to_curl_request($file, $request, $key);
|
|
$this->assertArrayHasKey($key, $request->_tmp_file_post_params);
|
|
$this->assertEquals($filepath, $request->_tmp_file_post_params[$key]->name);
|
|
}
|
|
|
|
/**
|
|
* Ensure that test_get_imageinfo_not_image returns false if the file
|
|
* passed was deemed to not be an image.
|
|
*
|
|
* @covers ::get_imageinfo
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_imageinfo_not_image() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'is_image_from_storedfile',
|
|
]);
|
|
|
|
$fs->expects($this->once())
|
|
->method('is_image_from_storedfile')
|
|
->with($this->equalTo($file))
|
|
->willReturn(false);
|
|
|
|
$this->assertFalse($fs->get_imageinfo($file));
|
|
}
|
|
|
|
/**
|
|
* Ensure that test_get_imageinfo_not_image returns imageinfo.
|
|
*
|
|
* @covers ::get_imageinfo
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_imageinfo() {
|
|
$filepath = '/path/to/file';
|
|
$filecontent = 'example content';
|
|
$expectedresult = (object) [];
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'is_image_from_storedfile',
|
|
'get_local_path_from_storedfile',
|
|
'get_imageinfo_from_path',
|
|
]);
|
|
|
|
$fs->expects($this->once())
|
|
->method('is_image_from_storedfile')
|
|
->with($this->equalTo($file))
|
|
->willReturn(true);
|
|
|
|
$fs->expects($this->once())
|
|
->method('get_local_path_from_storedfile')
|
|
->with($this->equalTo($file), $this->equalTo(true))
|
|
->willReturn($filepath);
|
|
|
|
$fs->expects($this->once())
|
|
->method('get_imageinfo_from_path')
|
|
->with($this->equalTo($filepath))
|
|
->willReturn($expectedresult);
|
|
|
|
$this->assertEquals($expectedresult, $fs->get_imageinfo($file));
|
|
}
|
|
|
|
/**
|
|
* Ensure that is_image_from_storedfile always returns false for an
|
|
* empty file size.
|
|
*
|
|
* @covers ::is_image_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_image_empty_filesize() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent, null, ['get_filesize']);
|
|
|
|
$file->expects($this->once())
|
|
->method('get_filesize')
|
|
->willReturn(0);
|
|
|
|
$fs = $this->get_testable_mock();
|
|
$this->assertFalse($fs->is_image_from_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Ensure that is_image_from_storedfile behaves correctly based on
|
|
* mimetype.
|
|
*
|
|
* @dataProvider is_image_from_storedfile_provider
|
|
* @param string $mimetype Mimetype to test
|
|
* @param bool $isimage Whether this mimetype should be detected as an image
|
|
* @covers ::is_image_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_is_image_from_storedfile_mimetype($mimetype, $isimage) {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent, null, ['get_mimetype']);
|
|
|
|
$file->expects($this->once())
|
|
->method('get_mimetype')
|
|
->willReturn($mimetype);
|
|
|
|
$fs = $this->get_testable_mock();
|
|
$this->assertEquals($isimage, $fs->is_image_from_storedfile($file));
|
|
}
|
|
|
|
/**
|
|
* Test that get_imageinfo_from_path returns an appropriate response
|
|
* for an image.
|
|
*
|
|
* @covers ::get_imageinfo_from_path
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_imageinfo_from_path() {
|
|
$filepath = __DIR__ . "/fixtures/testimage.jpg";
|
|
|
|
// Get the filesystem mock.
|
|
$fs = $this->get_testable_mock();
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs($fs, [$filepath]);
|
|
|
|
$this->assertArrayHasKey('width', $result);
|
|
$this->assertArrayHasKey('height', $result);
|
|
$this->assertArrayHasKey('mimetype', $result);
|
|
$this->assertEquals('image/jpeg', $result['mimetype']);
|
|
}
|
|
|
|
/**
|
|
* Test that get_imageinfo_from_path returns an appropriate response
|
|
* for a file which is not an image.
|
|
*
|
|
* @covers ::get_imageinfo_from_path
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_imageinfo_from_path_no_image() {
|
|
$filepath = __FILE__;
|
|
|
|
// Get the filesystem mock.
|
|
$fs = $this->get_testable_mock();
|
|
|
|
$method = new ReflectionMethod(file_system::class, 'get_imageinfo_from_path');
|
|
$method->setAccessible(true);
|
|
$result = $method->invokeArgs($fs, [$filepath]);
|
|
|
|
$this->assertFalse($result);
|
|
}
|
|
|
|
/**
|
|
* Ensure that get_content_file_handle returns a valid file handle.
|
|
*
|
|
* @covers ::get_content_file_handle
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_content_file_handle_default() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
|
$fs->method('get_remote_path_from_storedfile')
|
|
->willReturn(__FILE__);
|
|
|
|
// Note: We are unable to determine the mode in which the $fh was opened.
|
|
$fh = $fs->get_content_file_handle($file);
|
|
$this->assertTrue(is_resource($fh));
|
|
$this->assertEquals('stream', get_resource_type($fh));
|
|
fclose($fh);
|
|
}
|
|
|
|
/**
|
|
* Ensure that get_content_file_handle returns a valid file handle for a gz file.
|
|
*
|
|
* @covers ::get_content_file_handle
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_content_file_handle_gz() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$fs = $this->get_testable_mock(['get_local_path_from_storedfile']);
|
|
$fs->method('get_local_path_from_storedfile')
|
|
->willReturn(__DIR__ . "/fixtures/test.tgz");
|
|
|
|
// Note: We are unable to determine the mode in which the $fh was opened.
|
|
$fh = $fs->get_content_file_handle($file, stored_file::FILE_HANDLE_GZOPEN);
|
|
$this->assertTrue(is_resource($fh));
|
|
gzclose($fh);
|
|
}
|
|
|
|
/**
|
|
* Ensure that get_content_file_handle returns an exception when calling for a invalid file handle type.
|
|
*
|
|
* @covers ::get_content_file_handle
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_get_content_file_handle_invalid() {
|
|
$filecontent = 'example content';
|
|
$file = $this->get_stored_file($filecontent);
|
|
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
|
$fs->method('get_remote_path_from_storedfile')
|
|
->willReturn(__FILE__);
|
|
|
|
$this->expectException('coding_exception', 'Unexpected file handle type');
|
|
$fs->get_content_file_handle($file, -1);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_hash returns the correct mimetype with
|
|
* a file whose filename suggests mimetype.
|
|
*
|
|
* @covers ::mimetype_from_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_hash_using_filename() {
|
|
$filepath = '/path/to/file/not/currently/on/disk';
|
|
$filecontent = 'example content';
|
|
$filename = 'test.jpg';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_hash']);
|
|
$fs->method('get_remote_path_from_hash')->willReturn($filepath);
|
|
|
|
$result = $fs->mimetype_from_hash($contenthash, $filename);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_hash returns the correct mimetype with
|
|
* a locally available file whose filename does not suggest mimetype.
|
|
*
|
|
* @covers ::mimetype_from_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_hash_using_file_content() {
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
$filename = 'example';
|
|
|
|
$filepath = __DIR__ . "/fixtures/testimage.jpg";
|
|
$fs = $this->get_testable_mock(['get_local_path_from_hash']);
|
|
$fs->method('get_local_path_from_hash')->willReturn($filepath);
|
|
|
|
$result = $fs->mimetype_from_hash($contenthash, $filename);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_hash returns the correct mimetype with
|
|
* a remotely available file whose filename does not suggest mimetype.
|
|
*
|
|
* @covers ::mimetype_from_hash
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_hash_using_file_content_remote() {
|
|
$filepath = '/path/to/file/not/currently/on/disk';
|
|
$filecontent = 'example content';
|
|
$contenthash = file_storage::hash_from_string($filecontent);
|
|
$filename = 'example';
|
|
|
|
$filepath = __DIR__ . "/fixtures/testimage.jpg";
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'get_remote_path_from_hash',
|
|
'is_file_readable_locally_by_hash',
|
|
'get_local_path_from_hash',
|
|
]);
|
|
|
|
$fs->method('get_remote_path_from_hash')->willReturn('/path/to/remote/file');
|
|
$fs->method('is_file_readable_locally_by_hash')->willReturn(false);
|
|
$fs->method('get_local_path_from_hash')->willReturn($filepath);
|
|
|
|
$result = $fs->mimetype_from_hash($contenthash, $filename);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_storedfile returns the correct mimetype with
|
|
* a file whose filename suggests mimetype.
|
|
*
|
|
* @covers ::mimetype_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_storedfile_empty() {
|
|
$file = $this->get_stored_file('');
|
|
|
|
$fs = $this->get_testable_mock();
|
|
$result = $fs->mimetype_from_storedfile($file);
|
|
$this->assertNull($result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_storedfile returns the correct mimetype with
|
|
* a file whose filename suggests mimetype.
|
|
*
|
|
* @covers ::mimetype_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_storedfile_using_filename() {
|
|
$filepath = '/path/to/file/not/currently/on/disk';
|
|
$fs = $this->get_testable_mock(['get_remote_path_from_storedfile']);
|
|
$fs->method('get_remote_path_from_storedfile')->willReturn($filepath);
|
|
|
|
$file = $this->get_stored_file('example content', 'test.jpg');
|
|
|
|
$result = $fs->mimetype_from_storedfile($file);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_storedfile returns the correct mimetype with
|
|
* a locally available file whose filename does not suggest mimetype.
|
|
*
|
|
* @covers ::mimetype_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_storedfile_using_file_content() {
|
|
$filepath = __DIR__ . "/fixtures/testimage.jpg";
|
|
$fs = $this->get_testable_mock(['get_local_path_from_hash']);
|
|
$fs->method('get_local_path_from_hash')->willReturn($filepath);
|
|
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$result = $fs->mimetype_from_storedfile($file);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Test that mimetype_from_storedfile returns the correct mimetype with
|
|
* a remotely available file whose filename does not suggest mimetype.
|
|
*
|
|
* @covers ::mimetype_from_storedfile
|
|
* @covers ::<!public>
|
|
*/
|
|
public function test_mimetype_from_storedfile_using_file_content_remote() {
|
|
$filepath = __DIR__ . "/fixtures/testimage.jpg";
|
|
|
|
$fs = $this->get_testable_mock([
|
|
'is_file_readable_locally_by_hash',
|
|
'get_local_path_from_hash',
|
|
]);
|
|
|
|
$fs->method('is_file_readable_locally_by_hash')->willReturn(false);
|
|
$fs->method('get_local_path_from_hash')->will($this->onConsecutiveCalls('/path/to/remote/file', $filepath));
|
|
|
|
$file = $this->get_stored_file('example content');
|
|
|
|
$result = $fs->mimetype_from_storedfile($file);
|
|
$this->assertEquals('image/jpeg', $result);
|
|
}
|
|
|
|
/**
|
|
* Data Provider for is_image_from_storedfile tests.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function is_image_from_storedfile_provider() {
|
|
return array(
|
|
'Standard image' => array('image/png', true),
|
|
'Made up document/image' => array('document/image', false),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Data provider for get_local_path_from_storedfile tests.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_local_path_from_storedfile_provider() {
|
|
return [
|
|
'default args (nofetch)' => [
|
|
'args' => [],
|
|
'fetch' => 0,
|
|
],
|
|
'explicit: nofetch' => [
|
|
'args' => [false],
|
|
'fetch' => 0,
|
|
],
|
|
'explicit: fetch' => [
|
|
'args' => [true],
|
|
'fetch' => 1,
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|