<?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/>.
namespace core_h5p;
use core_h5p\file_storage;
use core_h5p\local\library\autoloader;
use core_h5p\helper;
use file_archive;
use moodle_exception;
use ReflectionMethod;
use stored_file;
use zip_archive;
/**
* Test class covering the H5PFileStorage interface implementation.
*
* @package core_h5p
* @category test
* @copyright 2019 Victor Deniz <victor@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @runTestsInSeparateProcesses
*/
class file_storage_test extends \advanced_testcase {
/** @var \core_h5p\file_storage H5P file storage instance */
protected $h5p_file_storage;
/** @var \file_storage Core Moodle file_storage associated to the H5P file_storage */
protected $h5p_fs_fs;
/** @var \context Moodle context of the H5P file_storage */
protected $h5p_fs_context;
/** @var string Path to temp directory */
protected $h5p_tempath;
/** @var \core_h5p_generator H5P generator instance */
protected $h5p_generator;
/** @var array $files an array used in the cache tests. */
protected $files = ['scripts' => [], 'styles' => []];
/** @var int $libraryid an id for the library. */
protected $libraryid = 1;
protected function setUp(): void {
parent::setUp();
$this->resetAfterTest(true);
autoloader::register();
// Fetch generator.
$generator = \testing_util::get_data_generator();
$this->h5p_generator = $generator->get_plugin_generator('core_h5p');
// Create file_storage_instance and create H5P temp directory.
$this->h5p_file_storage = new file_storage();
$this->h5p_tempath = $this->h5p_file_storage->getTmpPath();
check_dir_exists($this->h5p_tempath);
// Get value of protected properties.
$h5p_fs_rc = new \ReflectionClass(file_storage::class);
$h5p_file_storage_context = $h5p_fs_rc->getProperty('context');
$h5p_file_storage_context->setAccessible(true);
$this->h5p_fs_context = $h5p_file_storage_context->getValue($this->h5p_file_storage);
$h5p_file_storage_fs = $h5p_fs_rc->getProperty('fs');
$h5p_file_storage_fs->setAccessible(true);
$this->h5p_fs_fs = $h5p_file_storage_fs->getValue($this->h5p_file_storage);
}
/**
* Test that given the main directory of a library that all files are saved
* into the file system.
*/
public function test_saveLibrary(): void {
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,
$minorversion);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
// Check that files are in the Moodle file system.
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/", 'library.json');
$filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";
$this->assertEquals($filepath, $file->get_filepath());
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/scripts/", 'testlib.min.js');
$jsfilepath = "{$filepath}scripts/";
$this->assertEquals($jsfilepath, $file->get_filepath());
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/styles/", 'testlib.min.css');
$cssfilepath = "{$filepath}styles/";
$this->assertEquals($cssfilepath, $file->get_filepath());
}
/**
* Test that a content file can be saved.
*/
public function test_saveContent(): void {
$source = $this->h5p_tempath . '/' . 'content.json';
$this->h5p_generator->create_file($source);
$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
$this->assertEquals(file_storage::CONTENT_FILEAREA, $file->get_filearea());
$this->assertEquals('content.json', $file->get_filename());
$this->assertEquals(5, $file->get_itemid());
}
/**
* Test that content files located on the file system can be deleted.
*/
public function test_deleteContent(): void {
$source = $this->h5p_tempath . '/' . 'content.json';
$this->h5p_generator->create_file($source);
$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
$this->assertEquals('content.json', $file->get_filename());
// Now to delete the record.
$this->h5p_file_storage->deleteContent(['id' => 5]);
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
$this->assertFalse($file);
}
/**
* Test that returning a temp path returns what is expected by the h5p library.
*/
public function test_getTmpPath(): void {
$temparray = explode('/', $this->h5p_tempath);
$h5pdirectory = array_pop($temparray);
$this->assertTrue(stripos($h5pdirectory, 'h5p-') === 0);
}
/**
* Test that the content files can be exported to a specified location.
*/
public function test_exportContent(): void {
// Create a file to store.
$source = $this->h5p_tempath . '/' . 'content.json';
$this->h5p_generator->create_file($source);
$this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
$this->assertEquals('content.json', $file->get_filename());
// Now export it.
$destinationdirectory = $this->h5p_tempath . '/' . 'testdir';
check_dir_exists($destinationdirectory);
$this->h5p_file_storage->exportContent(5, $destinationdirectory);
// Check that there is a file now in that directory.
$contents = scandir($destinationdirectory);
$value = array_search('content.json', $contents);
$this->assertEquals('content.json', $contents[$value]);
}
/**
* Test that libraries on the file system can be exported to a specified location.
*/
public function test_exportLibrary(): void {
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,
$minorversion);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
$destinationdirectory = $this->h5p_tempath . '/' . 'testdir';
check_dir_exists($destinationdirectory);
$this->h5p_file_storage->exportLibrary($lib, $destinationdirectory);
$filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";
// There should be at least three items here (but could be more with . and ..).
$this->assertFileExists($destinationdirectory . $filepath . 'library.json');
$this->assertFileExists($destinationdirectory . $filepath . 'scripts/' . 'testlib.min.js');
$this->assertFileExists($destinationdirectory . $filepath . 'styles/' . 'testlib.min.css');
}
/**
* Test that an export file can be saved into the file system.
*/
public function test_saveExport(): void {
$filename = 'someexportedfile.h5p';
$source = $this->h5p_tempath . '/' . $filename;
$this->h5p_generator->create_file($source);
$this->h5p_file_storage->saveExport($source, $filename);
// Check out if the file is there.
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::EXPORT_FILEAREA, '0', '/', $filename);
$this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());
}
/**
* Test that an exort file can be deleted from the file system.
* @return [type] [description]
*/
public function test_deleteExport(): void {
$filename = 'someexportedfile.h5p';
$source = $this->h5p_tempath . '/' . $filename;
$this->h5p_generator->create_file($source);
$this->h5p_file_storage->saveExport($source, $filename);
// Check out if the file is there.
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::EXPORT_FILEAREA, '0', '/', $filename);
$this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());
// Time to delete.
$this->h5p_file_storage->deleteExport($filename);
// Check out if the file is there.
$file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::EXPORT_FILEAREA, '0', '/', $filename);
$this->assertFalse($file);
}
/**
* Test to check if an export file already exists on the file system.
*/
public function test_hasExport(): void {
$filename = 'someexportedfile.h5p';
$source = $this->h5p_tempath . '/' . $filename;
$this->h5p_generator->create_file($source);
// Check that it doesn't exist in the file system.
$this->assertFalse($this->h5p_file_storage->hasExport($filename));
$this->h5p_file_storage->saveExport($source, $filename);
// Now it should be present.
$this->assertTrue($this->h5p_file_storage->hasExport($filename));
}
/**
* Test that all the library files for an H5P activity can be concatenated into "cache" files. One for js and another for css.
*/
public function test_cacheAssets(): void {
$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
// Second library.
$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
$this->libraryid++;
$machinename = 'SuperTest';
$majorversion = 2;
$minorversion = 4;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
$this->h5p_file_storage->saveLibrary($lib);
$this->assertCount(2, $this->files['scripts']);
$this->assertCount(2, $this->files['styles']);
$key = 'testhashkey';
$this->h5p_file_storage->cacheAssets($this->files, $key);
$this->assertCount(1, $this->files['scripts']);
$this->assertCount(1, $this->files['styles']);
$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';
$this->assertEquals($expectedfile, $this->files['scripts'][0]->path);
$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';
$this->assertEquals($expectedfile, $this->files['styles'][0]->path);
}
/**
* Test that cached files can be retrieved via a key.
*/
public function test_getCachedAssets() {
$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
// Second library.
$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
$this->libraryid++;
$machinename = 'SuperTest';
$majorversion = 2;
$minorversion = 4;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
$this->h5p_file_storage->saveLibrary($lib);
$this->assertCount(2, $this->files['scripts']);
$this->assertCount(2, $this->files['styles']);
$key = 'testhashkey';
$this->h5p_file_storage->cacheAssets($this->files, $key);
$testarray = $this->h5p_file_storage->getCachedAssets($key);
$this->assertCount(1, $testarray['scripts']);
$this->assertCount(1, $testarray['styles']);
$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';
$this->assertEquals($expectedfile, $testarray['scripts'][0]->path);
$expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';
$this->assertEquals($expectedfile, $testarray['styles'][0]->path);
}
/**
* Test that cache files in the files system can be removed.
*/
public function test_deleteCachedAssets(): void {
$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
// Second library.
$basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
$this->libraryid++;
$machinename = 'SuperTest';
$majorversion = 2;
$minorversion = 4;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
$this->h5p_file_storage->saveLibrary($lib);
$this->assertCount(2, $this->files['scripts']);
$this->assertCount(2, $this->files['styles']);
$key = 'testhashkey';
$this->h5p_file_storage->cacheAssets($this->files, $key);
$testarray = $this->h5p_file_storage->getCachedAssets($key);
$this->assertCount(1, $testarray['scripts']);
$this->assertCount(1, $testarray['styles']);
// Time to delete.
$this->h5p_file_storage->deleteCachedAssets([$key]);
$testarray = $this->h5p_file_storage->getCachedAssets($key);
$this->assertNull($testarray);
}
/**
* Retrieve content from a file given a specific path.
*/
public function test_getContent() {
$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
array_push($this->files['scripts'], ...$libfiles['scripts']);
array_push($this->files['styles'], ...$libfiles['styles']);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
$content = $this->h5p_file_storage->getContent($this->files['scripts'][0]->path);
// The file content is created based on the file system path (\core_h5p_generator::create_file).
$expectedcontent = hash("md5", $basedirectory. '/' . 'scripts' . '/' . 'testlib.min.js');
$this->assertEquals($expectedcontent, $content);
}
/**
* Test that an upgrade script can be found on the file system.
*/
public function test_getUpgradeScript() {
// Upload an upgrade file.
$machinename = 'TestLib';
$majorversion = 3;
$minorversion = 1;
$filepath = '/' . "{$machinename}-{$majorversion}.{$minorversion}" . '/';
$fs = get_file_storage();
$filerecord = [
'contextid' => \context_system::instance()->id,
'component' => file_storage::COMPONENT,
'filearea' => file_storage::LIBRARY_FILEAREA,
'itemid' => 15,
'filepath' => $filepath,
'filename' => 'upgrade.js'
];
$filestorage = new file_storage();
$fs->create_file_from_string($filerecord, 'test string info');
$expectedfilepath = '/' . file_storage::LIBRARY_FILEAREA . $filepath . 'upgrade.js';
$this->assertEquals($expectedfilepath, $filestorage->getUpgradeScript($machinename, $majorversion, $minorversion));
$this->assertNull($filestorage->getUpgradeScript($machinename, $majorversion, 7));
}
/**
* Test that information from a source can be saved to the specified path.
* The zip file has the following contents
* - h5ptest
* |- content
* | |- content.json
* |- testFont
* | |- testfont.min.css
* |- testJavaScript
* | |- testscript.min.js
* |- h5p.json
*/
public function test_saveFileFromZip() {
$ziparchive = new zip_archive();
$path = __DIR__ . '/fixtures/h5ptest.zip';
$result = $ziparchive->open($path, file_archive::OPEN);
$files = $ziparchive->list_files();
foreach ($files as $file) {
if (!$file->is_directory) {
$stream = $ziparchive->get_stream($file->index);
$items = explode('/', $file->pathname);
array_shift($items);
$path = implode('/', $items);
$this->h5p_file_storage->saveFileFromZip($this->h5p_tempath, $path, $stream);
$filestocheck[] = $path;
}
}
$ziparchive->close();
foreach ($filestocheck as $filetocheck) {
$pathtocheck = $this->h5p_tempath .'/'. $filetocheck;
$this->assertFileExists($pathtocheck);
}
}
/**
* Test that a library is fully deleted from the file system
*/
public function test_delete_library() {
$basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
$machinename = 'TestLib';
$majorversion = 1;
$minorversion = 0;
[$lib, $files] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib);
// Save a second library to ensure we aren't deleting all libraries, but just the one specified.
$basedirectory = $this->h5p_tempath . '/' . 'awesomelib-2.1';
$this->libraryid++;
$machinename = 'AwesomeLib';
$majorversion = 2;
$minorversion = 1;
[$lib2, $files2] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
$minorversion);
// Now run the API call.
$this->h5p_file_storage->saveLibrary($lib2);
$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA);
$this->assertCount(14, $files);
$this->h5p_file_storage->delete_library($lib);
// Let's look at the records.
$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA);
$this->assertCount(7, $files);
// Check that the db count is still the same after setting the libraryId to false.
$lib['libraryId'] = false;
$this->h5p_file_storage->delete_library($lib);
$files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::LIBRARY_FILEAREA);
$this->assertCount(7, $files);
}
/**
* Test get_icon_url() function behaviour.
*
* @dataProvider get_icon_url_provider
* @param string $filename The name of the H5P file to load.
* @param bool $expected Whether the icon should exist or not.
*/
public function test_get_icon_url(string $filename, bool $expected): void {
global $DB;
$this->resetAfterTest();
$factory = new \core_h5p\factory();
$admin = get_admin();
// Prepare a valid .H5P file.
$path = __DIR__ . '/fixtures/'.$filename;
// Libraries can be updated when the file has been created by admin, even when the current user is not the admin.
$this->setUser($admin);
$file = helper::create_fake_stored_file_from_path($path, (int)$admin->id);
$factory->get_framework()->set_file($file);
$config = (object)[
'frame' => 1,
'export' => 1,
'embed' => 0,
'copyright' => 0,
];
$h5pid = helper::save_h5p($factory, $file, $config);
$h5p = $DB->get_record('h5p', ['id' => $h5pid]);
$h5plib = $DB->get_record('h5p_libraries', ['id' => $h5p->mainlibraryid]);
$iconurl = $this->h5p_file_storage->get_icon_url(
$h5plib->id,
$h5plib->machinename,
$h5plib->majorversion,
$h5plib->minorversion
);
if ($expected) {
$this->assertStringContainsString(file_storage::ICON_FILENAME, $iconurl);
} else {
$this->assertFalse($iconurl);
}
}
/**
* Data provider for test_get_icon_url().
*
* @return array
*/
public function get_icon_url_provider(): array {
return [
'Icon included' => [
'filltheblanks.h5p',
true,
],
'Icon not included' => [
< 'greeting-card-887.h5p',
> 'greeting-card.h5p',
false,
],
];
}
/**
* Test the private method get_file, a wrapper for getting an H5P content file.
*/
public function test_get_file(): void {
$this->setAdminUser();
$file = 'img/fake.png';
$h5pcontentid = 3;
// Add a file to a H5P content.
$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);
// Set get_file method accessibility.
$method = new ReflectionMethod(file_storage::class, 'get_file');
$method->setAccessible(true);
$contentfile = $method->invoke(new file_storage(), file_storage::CONTENT_FILEAREA, $h5pcontentid, $file);
// Check that it returns an instance of store_file.
$this->assertInstanceOf('stored_file', $contentfile);
// Add a file to editor.
$this->h5p_generator->create_content_file($file, 'draft', $h5pcontentid);
$editorfile = $method->invoke(new file_storage(), 'draft', $h5pcontentid, $file);
// Check that it returns an instance of store_file.
$this->assertInstanceOf('stored_file', $editorfile);
}
/**
* Test that a single file is added to Moodle files.
*/
public function test_move_file(): void {
// Create temp folder.
$tempfolder = make_request_directory(false);
// Create H5P content folder.
$filepath = '/img/';
$filename = 'fake.png';
$h5pcontentfolder = $tempfolder . '/fakeH5Pcontent/content' . $filepath;
if (!check_dir_exists($h5pcontentfolder, true, true)) {
throw new moodle_exception('error_creating_temp_dir', 'error', $h5pcontentfolder);
}
$file = $h5pcontentfolder . $filename;
touch($file);
$h5pcontentid = 3;
// Check the file doesn't exist in Moodle files.
$this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
// Set get_file method accessibility.
$method = new ReflectionMethod(file_storage::class, 'move_file');
$method->setAccessible(true);
$method->invoke(new file_storage(), $file, $h5pcontentid);
// Check the file exist in Moodle files.
$this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
}
/**
* Test that a file is copied from another H5P content or the H5P editor.
*
* @return void
*/
public function test_cloneContentFile(): void {
$admin = get_admin();
$usercontext = \context_user::instance($admin->id);
$this->setUser($admin);
// Upload a file to the editor.
$file = 'images/fake.jpg';
$filepath = '/'.dirname($file).'/';
$filename = basename($file);
$content = 'abcd';
$filerecord = array(
'contextid' => $usercontext->id,
'component' => 'user',
'filearea' => 'draft',
'itemid' => 0,
'filepath' => $filepath,
'filename' => $filename,
);
$this->h5p_fs_fs->create_file_from_string($filerecord, $content);
// Target H5P content, where the file will be cloned.
$targetcontent = new \stdClass();
$targetcontent->id = 999;
// Check the file doesn't exists before cloning.
$this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
// Copy file from the editor.
$this->h5p_file_storage->cloneContentFile($file, 'editor', $targetcontent);
// Check the file exists after cloning.
$this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
// Simulate that an H5P content, with id $sourcecontentid, has a file.
$file = 'images/fake2.jpg';
$filepath = '/'.dirname($file).'/';
$filename = basename($file);
$sourcecontentid = 111;
$filerecord['contextid'] = $this->h5p_fs_context->id;
$filerecord['component'] = file_storage::COMPONENT;
$filerecord['filearea'] = file_storage::CONTENT_FILEAREA;
$filerecord['itemid'] = $sourcecontentid;
$filerecord['filepath'] = $filepath;
$filerecord['filename'] = $filename;
$this->h5p_fs_fs->create_file_from_string($filerecord, $content);
// Check the file doesn't exists before cloning.
$this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
// Copy file from another H5P content.
$this->h5p_file_storage->cloneContentFile($file, $sourcecontentid, $targetcontent);
// Check the file exists after cloning.
$this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
}
/**
* Test that a given file exists in an H5P content.
*
* @return void
*/
public function test_getContentFile(): void {
$file = 'img/fake.png';
$contentid = 3;
// Add a file to a H5P content.
$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $contentid);
// Get an existing file id.
$fileid = $this->h5p_file_storage->getContentFile($file, $contentid);
$this->assertNotNull($fileid);
// Try to get a nonexistent file.
$fileid = $this->h5p_file_storage->getContentFile($file, 5);
$this->assertNull($fileid);
}
/**
* Tests that the content folder of an H5P content is imported in the Moodle filesystem.
*/
public function test_moveContentDiretory(): void {
// Create temp folder.
$tempfolder = make_request_directory(false);
// Create H5P content folder.
$h5pcontentfolder = $tempfolder . '/fakeH5Pcontent';
$contentfolder = $h5pcontentfolder . '/content';
if (!check_dir_exists($contentfolder, true, true)) {
throw new moodle_exception('error_creating_temp_dir', 'error', $contentfolder);
}
// Add content.json file.
touch($contentfolder . 'content.json');
// Create several folders and files inside content folder.
$filesexpected = array();
$numfolders = random_int(2, 5);
for ($numfolder = 1; $numfolder < $numfolders; $numfolder++) {
$foldername = '/folder' . $numfolder;
$newfolder = $contentfolder . $foldername;
if (!check_dir_exists($newfolder, true, true)) {
throw new moodle_exception('error_creating_temp_dir', 'error', $newfolder);
}
$numfiles = random_int(2, 5);
for ($numfile = 1; $numfile < $numfiles; $numfile++) {
$filename = '/file' . $numfile . '.ext';
touch($newfolder . $filename);
$filesexpected[] = $foldername . $filename;
}
}
$targeth5pcontentid = 111;
$this->h5p_file_storage->moveContentDirectory($h5pcontentfolder, $targeth5pcontentid);
// Get database records.
$files = $this->h5p_fs_fs->get_area_files(
$this->h5p_fs_context->id,
file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA,
$targeth5pcontentid,
'filepath, filename',
false
);
$filepaths = array_map(static function(stored_file $file): string {
return $file->get_filepath() . $file->get_filename();
}, $files);
// Check that created files match with database records.
$this->assertEquals($filesexpected, array_values($filepaths));
}
/**
* Test that an H5P content file is removed.
*/
public function test_removeContentFile(): void {
$file = 'img/fake.png';
$filepath = '/' . dirname($file) . '/';
$filename = basename($file);
$h5pcontentid = 3;
// Add a file to a H5P content.
$this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);
// Check the file exists.
$this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
$this->h5p_file_storage->removeContentFile($file, $h5pcontentid);
// Check the file doesn't exists.
$this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
}
}