Merge branch 'MDL-69520-master' of git://github.com/sarjona/moodle
[moodle.git] / h5p / tests / framework_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Testing the H5PFrameworkInterface interface implementation.
19  *
20  * @package    core_h5p
21  * @category   test
22  * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace core_h5p;
28 use core_collator;
30 /**
31  *
32  * Test class covering the H5PFrameworkInterface interface implementation.
33  *
34  * @package    core_h5p
35  * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  * @runTestsInSeparateProcesses
38  */
39 class framework_testcase extends \advanced_testcase {
41     /** @var \core_h5p\framework */
42     private $framework;
44     /**
45      * Set up function for tests.
46      */
47     public function setUp() {
48         $factory = new \core_h5p\factory();
49         $this->framework = $factory->get_framework();
50     }
52     /**
53      * Test the behaviour of getPlatformInfo().
54      */
55     public function test_getPlatformInfo() {
56         global $CFG;
58         $platforminfo = $this->framework->getPlatformInfo();
60         $expected = array(
61             'name' => 'Moodle',
62             'version' => $CFG->version,
63             'h5pVersion' => $CFG->version
64         );
66         $this->assertEquals($expected, $platforminfo);
67     }
69     /**
70      * Test the behaviour of fetchExternalData() when the store path is not defined.
71      *
72      * This test is intensive and requires downloading content of an external file,
73      * therefore it might take longer time to execute.
74      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
75      */
76     public function test_fetchExternalData_no_path_defined() {
78         if (!PHPUNIT_LONGTEST) {
79             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
80         }
82         $this->resetAfterTest();
84         $library = 'H5P.Accordion';
85         // Provide a valid URL to an external H5P content.
86         $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
88         // Test fetching an external H5P content without defining a path to where the file should be stored.
89         $data = $this->framework->fetchExternalData($url, null, true);
91         // The response should not be empty and return true if the file was successfully downloaded.
92         $this->assertNotEmpty($data);
93         $this->assertTrue($data);
95         $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
96         // The uploaded file should exist on the filesystem.
97         $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
98     }
100     /**
101      * Test the behaviour of fetchExternalData() when the store path is defined.
102      *
103      * This test is intensive and requires downloading content of an external file,
104      * therefore it might take longer time to execute.
105      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
106      */
107     public function test_fetchExternalData_path_defined() {
108         global $CFG;
110         if (!PHPUNIT_LONGTEST) {
111             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
112         }
114         $this->resetAfterTest();
116         $library = 'H5P.Accordion';
117         // Provide a valid URL to an external H5P content.
118         $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
120         $h5pfolderpath = $CFG->tempdir . uniqid('/h5p-');
122         $data = $this->framework->fetchExternalData($url, null, true, $h5pfolderpath . '.h5p');
124         // The response should not be empty and return true if the content has been successfully saved to a file.
125         $this->assertNotEmpty($data);
126         $this->assertTrue($data);
128         // The uploaded file should exist on the filesystem.
129         $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
130     }
132     /**
133      * Test the behaviour of fetchExternalData() when the URL is pointing to an external file that is
134      * not an h5p content.
135      *
136      * This test is intensive and requires downloading content of an external file,
137      * therefore it might take longer time to execute.
138      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
139      */
140     public function test_fetchExternalData_url_not_h5p() {
142         if (!PHPUNIT_LONGTEST) {
143             // This test is intensive and requires downloading the content of an external file.
144             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
145         }
147         $this->resetAfterTest();
149         // Provide an URL to an external file that is not an H5P content file.
150         $url = $this->getExternalTestFileUrl('/h5pcontenttypes.json');
152         $data = $this->framework->fetchExternalData($url, null, true);
154         // The response should not be empty and return true if the content has been successfully saved to a file.
155         $this->assertNotEmpty($data);
156         $this->assertTrue($data);
158         // The uploaded file should exist on the filesystem with it's original extension.
159         // NOTE: The file would be later validated by the H5P Validator.
160         $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
161         $this->assertTrue(file_exists($h5pfolderpath . '.json'));
162     }
164     /**
165      * Test the behaviour of fetchExternalData() when the URL is invalid.
166      */
167     public function test_fetchExternalData_url_invalid() {
168         // Provide an invalid URL to an external file.
169         $url = "someprotocol://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
171         $data = $this->framework->fetchExternalData($url, null, true);
173         // The response should be empty.
174         $this->assertEmpty($data);
175     }
177     /**
178      * Test the behaviour of setLibraryTutorialUrl().
179      */
180     public function test_setLibraryTutorialUrl() {
181         global $DB;
183         $this->resetAfterTest();
185         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
187         // Create several libraries records.
188         $lib1 = $generator->create_library_record('Library1', 'Lib1', 1, 0, 1, '', null, 'http://tutorial1.org',
189             'http://example.org');
190         $lib2 = $generator->create_library_record('Library2', 'Lib2', 2, 0, 1, '', null, 'http://tutorial2.org');
191         $lib3 = $generator->create_library_record('Library3', 'Lib3', 3, 0);
193         // Check only lib1 tutorial URL is updated.
194         $url = 'https://newtutorial.cat';
195         $this->framework->setLibraryTutorialUrl($lib1->machinename, $url);
197         $libraries = $DB->get_records('h5p_libraries');
198         $this->assertEquals($libraries[$lib1->id]->tutorial, $url);
199         $this->assertNotEquals($libraries[$lib2->id]->tutorial, $url);
201         // Check lib1 tutorial URL is set to null.
202         $this->framework->setLibraryTutorialUrl($lib1->machinename, null);
204         $libraries = $DB->get_records('h5p_libraries');
205         $this->assertCount(3, $libraries);
206         $this->assertNull($libraries[$lib1->id]->tutorial);
208         // Check no tutorial URL is set if library name doesn't exist.
209         $this->framework->setLibraryTutorialUrl('Unexisting library', $url);
211         $libraries = $DB->get_records('h5p_libraries');
212         $this->assertCount(3, $libraries);
213         $this->assertNull($libraries[$lib1->id]->tutorial);
214         $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
215         $this->assertNull($libraries[$lib3->id]->tutorial);
217         // Check tutorial is set as expected when it was null.
218         $this->framework->setLibraryTutorialUrl($lib3->machinename, $url);
220         $libraries = $DB->get_records('h5p_libraries');
221         $this->assertEquals($libraries[$lib3->id]->tutorial, $url);
222         $this->assertNull($libraries[$lib1->id]->tutorial);
223         $this->assertEquals($libraries[$lib2->id]->tutorial, 'http://tutorial2.org');
224     }
226     /**
227      * Test the behaviour of setErrorMessage().
228      */
229     public function test_setErrorMessage() {
230         // Set an error message and an error code.
231         $message = "Error message";
232         $code = '404';
234         // Set an error message.
235         $this->framework->setErrorMessage($message, $code);
237         // Get the error messages.
238         $errormessages = $this->framework->getMessages('error');
240         $expected = new \stdClass();
241         $expected->code = 404;
242         $expected->message = 'Error message';
244         $this->assertEquals($expected, $errormessages[0]);
245     }
247     /**
248      * Test the behaviour of setInfoMessage().
249      */
250     public function test_setInfoMessage() {
251         $message = "Info message";
253         // Set an info message.
254         $this->framework->setInfoMessage($message);
256         // Get the info messages.
257         $infomessages = $this->framework->getMessages('info');
259         $expected = 'Info message';
261         $this->assertEquals($expected, $infomessages[0]);
262     }
264     /**
265      * Test the behaviour of getMessages() when requesting the info messages.
266      */
267     public function test_getMessages_info() {
268         // Set an info message.
269         $this->framework->setInfoMessage("Info message");
270         // Set an error message.
271         $this->framework->setErrorMessage("Error message 1", 404);
273         // Get the info messages.
274         $infomessages = $this->framework->getMessages('info');
276         $expected = 'Info message';
278         // Make sure that only the info message has been returned.
279         $this->assertCount(1, $infomessages);
280         $this->assertEquals($expected, $infomessages[0]);
282         $infomessages = $this->framework->getMessages('info');
284         // Make sure the info messages have now been removed.
285         $this->assertEmpty($infomessages);
286     }
288     /**
289      * Test the behaviour of getMessages() when requesting the error messages.
290      */
291     public function test_getMessages_error() {
292         // Set an info message.
293         $this->framework->setInfoMessage("Info message");
294         // Set an error message.
295         $this->framework->setErrorMessage("Error message 1", 404);
296         // Set another error message.
297         $this->framework->setErrorMessage("Error message 2", 403);
299         // Get the error messages.
300         $errormessages = $this->framework->getMessages('error');
302         // Make sure that only the error messages are being returned.
303         $this->assertEquals(2, count($errormessages));
305         $expected1 = (object) [
306             'code' => 404,
307             'message' => 'Error message 1'
308         ];
310         $expected2 = (object) [
311             'code' => 403,
312             'message' => 'Error message 2'
313         ];
315         $this->assertEquals($expected1, $errormessages[0]);
316         $this->assertEquals($expected2, $errormessages[1]);
318         $errormessages = $this->framework->getMessages('error');
320         // Make sure the info messages have now been removed.
321         $this->assertEmpty($errormessages);
322     }
324     /**
325      * Test the behaviour of t() when translating existing string that does not require any arguments.
326      */
327     public function test_t_existing_string_no_args() {
328         // Existing language string without passed arguments.
329         $translation = $this->framework->t('No copyright information available for this content.');
331         // Make sure the string translation has been returned.
332         $this->assertEquals('No copyright information available for this content.', $translation);
333     }
335     /**
336      * Test the behaviour of t() when translating existing string that does require parameters.
337      */
338     public function test_t_existing_string_args() {
339         // Existing language string with passed arguments.
340         $translation = $this->framework->t('Illegal option %option in %library',
341             ['%option' => 'example', '%library' => 'Test library']);
343         // Make sure the string translation has been returned.
344         $this->assertEquals('Illegal option example in Test library', $translation);
345     }
347     /**
348      * Test the behaviour of t() when translating non-existent string.
349      */
350     public function test_t_non_existent_string() {
351         // Non-existing language string.
352         $message = 'Random message %option';
354         $translation = $this->framework->t($message);
356         // Make sure a debugging message is triggered.
357         $this->assertDebuggingCalled("String translation cannot be found. Please add a string definition for '" .
358             $message . "' in the core_h5p component.");
359         // As the string does not exist in the mapping array, make sure the passed message is returned.
360         $this->assertEquals($message, $translation);
361     }
363     /**
364      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
365      * the folder name is parsable.
366      **/
367     public function test_getLibraryFileUrl() {
368         global $CFG;
370         $this->resetAfterTest();
372         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
373         // Create a library record.
374         $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
376         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/library.json";
378         // Get the URL of a file from an existing library. The provided folder name is parsable.
379         $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
381         // Make sure the expected URL is returned.
382         $this->assertEquals($expected, $actual);
383     }
385     /**
386      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a non-existent library and
387      * the folder name is parsable.
388      **/
389     public function test_getLibraryFileUrl_non_existent_library() {
390         $this->resetAfterTest();
392         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
393         // Create a library record.
394         $generator->create_library_record('Library', 'Lib', 1, 1);
396         // Get the URL of a file from a non-existent library. The provided folder name is parsable.
397         $actual = $this->framework->getLibraryFileUrl('Library2-1.1', 'library.json');
399         // Make sure a debugging message is triggered.
400         $this->assertDebuggingCalled('The library "Library2-1.1" does not exist.');
402         // Make sure that an URL is not returned.
403         $this->assertEquals(null, $actual);
404     }
406     /**
407      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
408      * the folder name is not parsable.
409      **/
410     public function test_getLibraryFileUrl_not_parsable_folder_name() {
411         $this->resetAfterTest();
413         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
414         // Create a library record.
415         $generator->create_library_record('Library', 'Lib', 1, 1);
417         // Get the URL of a file from an existing library. The provided folder name is not parsable.
418         $actual = $this->framework->getLibraryFileUrl('Library1.1', 'library.json');
420         // Make sure a debugging message is triggered.
421         $this->assertDebuggingCalled(
422             'The provided string value "Library1.1" is not a valid name for a library folder.');
424         // Make sure that an URL is not returned.
425         $this->assertEquals(null, $actual);
426     }
428     /**
429      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
430      * versions and the folder name is parsable.
431      **/
432     public function test_getLibraryFileUrl_library_has_multiple_versions() {
433         global $CFG;
435         $this->resetAfterTest();
437         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
438         // Create library records with a different minor version.
439         $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1);
440         $lib2 = $generator->create_library_record('Library', 'Lib', 1, 3);
442         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.3/library.json";
444         // Get the URL of a file from an existing library (Library 1.3). The provided folder name is parsable.
445         $actual = $this->framework->getLibraryFileUrl('Library-1.3', 'library.json');
447         // Make sure the proper URL (from the requested library version) is returned.
448         $this->assertEquals($expected, $actual);
449     }
451     /**
452      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
453      * patch versions and the folder name is parsable.
454      **/
455     public function test_getLibraryFileUrl_library_has_multiple_patch_versions() {
456         global $CFG;
458         $this->resetAfterTest();
460         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
461         // Create library records with a different patch version.
462         $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
463         $lib2 = $generator->create_library_record('Library', 'Lib', 1, 1, 4);
464         $lib3 = $generator->create_library_record('Library', 'Lib', 1, 1, 3);
466         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.1/library.json";
468         // Get the URL of a file from an existing library. The provided folder name is parsable.
469         $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
471         // Make sure the proper URL (from the latest library patch) is returned.
472         $this->assertEquals($expected, $actual);
473     }
475     /**
476      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a sub-folder
477      * of an existing library and the folder name is parsable.
478      **/
479     public function test_getLibraryFileUrl_library_subfolder() {
480         global $CFG;
482         $this->resetAfterTest();
484         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
485         // Create a library record.
486         $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
488         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/css/example.css";
490         // Get the URL of a file from a sub-folder from an existing library. The provided folder name is parsable.
491         $actual = $this->framework->getLibraryFileUrl('Library-1.1/css', 'example.css');
493         // Make sure the proper URL is returned.
494         $this->assertEquals($expected, $actual);
495     }
497     /**
498      * Test the behaviour of loadAddons().
499      */
500     public function test_loadAddons() {
501         $this->resetAfterTest();
503         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
505         // Create a Library addon (1.1).
506         $generator->create_library_record('Library', 'Lib', 1, 1, 2,
507             '', '/regex1/');
508         // Create a Library addon (1.3).
509         $generator->create_library_record('Library', 'Lib', 1, 3, 2,
510             '', '/regex2/');
511         // Create a Library addon (1.2).
512         $generator->create_library_record('Library', 'Lib', 1, 2, 2,
513             '', '/regex3/');
514         // Create a Library1 addon (1.2)
515         $generator->create_library_record('Library1', 'Lib1', 1, 2, 2,
516             '', '/regex11/');
518         // Load the latest version of each addon.
519         $addons = $this->framework->loadAddons();
521         // The addons array should return 2 results (Library and Library1 addon).
522         $this->assertCount(2, $addons);
524         // Ensure the addons array is consistently ordered before asserting their contents.
525         core_collator::asort_array_of_arrays_by_key($addons, 'machineName');
526         [$addonone, $addontwo] = array_values($addons);
528         // Make sure the version 1.3 is the latest 'Library' addon version.
529         $this->assertEquals('Library', $addonone['machineName']);
530         $this->assertEquals(1, $addonone['majorVersion']);
531         $this->assertEquals(3, $addonone['minorVersion']);
533         // Make sure the version 1.2 is the latest 'Library1' addon version.
534         $this->assertEquals('Library1', $addontwo['machineName']);
535         $this->assertEquals(1, $addontwo['majorVersion']);
536         $this->assertEquals(2, $addontwo['minorVersion']);
537     }
539     /**
540      * Test the behaviour of loadLibraries().
541      */
542     public function test_loadLibraries() {
543         $this->resetAfterTest();
545         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
547         // Generate h5p related data.
548         $generator->generate_h5p_data();
550         // Load all libraries.
551         $libraries = $this->framework->loadLibraries();
553         // Make sure all libraries are returned.
554         $this->assertNotEmpty($libraries);
555         $this->assertCount(6, $libraries);
556         $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
557         $this->assertEquals('1', $libraries['MainLibrary'][0]->major_version);
558         $this->assertEquals('0', $libraries['MainLibrary'][0]->minor_version);
559         $this->assertEquals('1', $libraries['MainLibrary'][0]->patch_version);
560     }
562     /**
563      * Test the behaviour of test_getLibraryId() when requesting an existing machine name.
564      */
565     public function test_getLibraryId_existing_machine_name() {
566         $this->resetAfterTest();
568         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
570         // Create a library.
571         $lib = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
573         // Request the library ID of the library with machine name 'Library'.
574         $libraryid = $this->framework->getLibraryId('Library');
576         // Make sure the library ID is being returned.
577         $this->assertNotFalse($libraryid);
578         $this->assertEquals($lib->id, $libraryid);
579     }
581     /**
582      * Test the behaviour of test_getLibraryId() when requesting a non-existent machine name.
583      */
584     public function test_getLibraryId_non_existent_machine_name() {
585         $this->resetAfterTest();
587         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
589         // Create a library.
590         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
592         // Request the library ID of the library with machinename => 'TestLibrary' (non-existent).
593         $libraryid = $this->framework->getLibraryId('TestLibrary');
595         // Make sure the library ID not being returned.
596         $this->assertFalse($libraryid);
597     }
599     /**
600      * Test the behaviour of test_getLibraryId() when requesting a non-existent major version.
601      */
602     public function test_getLibraryId_non_existent_major_version() {
603         $this->resetAfterTest();
605         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
607         // Create a library.
608         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
610         // Request the library ID of the library with machine name => 'Library', majorversion => 2 (non-existent).
611         $libraryid = $this->framework->getLibraryId('Library', 2);
613         // Make sure the library ID not being returned.
614         $this->assertFalse($libraryid);
615     }
617     /**
618      * Test the behaviour of test_getLibraryId() when requesting a non-existent minor version.
619      */
620     public function test_getLibraryId_non_existent_minor_version() {
621         $this->resetAfterTest();
623         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
625         // Create a library.
626         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
628         // Request the library ID of the library with machine name => 'Library',
629         // majorversion => 1,  minorversion => 2 (non-existent).
630         $libraryid = $this->framework->getLibraryId('Library', 1, 2);
632         // Make sure the library ID not being returned.
633         $this->assertFalse($libraryid);
634     }
636     /**
637      * Test the behaviour of isPatchedLibrary().
638      *
639      * @dataProvider test_isPatchedLibrary_provider
640      * @param array $libraryrecords Array containing data for the library creation
641      * @param array $testlibrary Array containing the test library data
642      * @param bool $expected The expectation whether the library is patched or not
643      **/
644     public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary, bool $expected): void {
645         $this->resetAfterTest();
647         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
649         foreach ($libraryrecords as $library) {
650             call_user_func_array([$generator, 'create_library_record'], $library);
651         }
653         $this->assertEquals($expected, $this->framework->isPatchedLibrary($testlibrary));
654     }
656     /**
657      * Data provider for test_isPatchedLibrary().
658      *
659      * @return array
660      */
661     public function test_isPatchedLibrary_provider(): array {
662         return [
663             'Unpatched library. No different versioning' => [
664                 [
665                     ['TestLibrary', 'Test', 1, 1, 2],
666                 ],
667                 [
668                     'machineName' => 'TestLibrary',
669                     'majorVersion' => 1,
670                     'minorVersion' => 1,
671                     'patchVersion' => 2
672                 ],
673                 false,
674             ],
675             'Major version identical; Minor version identical; Patch version newer' => [
676                 [
677                     ['TestLibrary', 'Test', 1, 1, 2],
678                 ],
679                 [
680                     'machineName' => 'TestLibrary',
681                     'majorVersion' => 1,
682                     'minorVersion' => 1,
683                     'patchVersion' => 3
684                 ],
685                 true,
686             ],
687             'Major version identical; Minor version newer; Patch version newer' => [
688                 [
689                     ['TestLibrary', 'Test', 1, 1, 2],
690                 ],
691                 [
692                     'machineName' => 'TestLibrary',
693                     'majorVersion' => 1,
694                     'minorVersion' => 2,
695                     'patchVersion' => 3
696                 ],
697                 false,
698             ],
699             'Major version identical; Minor version identical; Patch version older' => [
700                 [
701                     ['TestLibrary', 'Test', 1, 1, 2],
702                 ],
703                 [
704                     'machineName' => 'TestLibrary',
705                     'majorVersion' => 1,
706                     'minorVersion' => 1,
707                     'patchVersion' => 1
708                 ],
709                 false,
710             ],
711             'Major version identical; Minor version newer; Patch version older' => [
712                 [
713                     ['TestLibrary', 'Test', 1, 1, 2],
714                 ],
715                 [
716                     'machineName' => 'TestLibrary',
717                     'majorVersion' => 1,
718                     'minorVersion' => 2,
719                     'patchVersion' => 1
720                 ],
721                 false,
722             ],
723             'Major version newer; Minor version identical; Patch version older' => [
724                 [
725                     ['TestLibrary', 'Test', 1, 1, 2],
726                 ],
727                 [
728                     'machineName' => 'TestLibrary',
729                     'majorVersion' => 2,
730                     'minorVersion' => 1,
731                     'patchVersion' => 1
732                 ],
733                 false,
734             ],
735             'Major version newer; Minor version identical; Patch version newer' => [
736                 [
737                     ['TestLibrary', 'Test', 1, 1, 2],
738                 ],
739                 [
740                     'machineName' => 'TestLibrary',
741                     'majorVersion' => 2,
742                     'minorVersion' => 1,
743                     'patchVersion' => 3
744                 ],
745                 false,
746             ],
748             'Major version older; Minor version identical; Patch version older' => [
749                 [
750                     ['TestLibrary', 'Test', 1, 1, 2],
751                 ],
752                 [
753                     'machineName' => 'TestLibrary',
754                     'majorVersion' => 0,
755                     'minorVersion' => 1,
756                     'patchVersion' => 1
757                 ],
758                 false,
759             ],
760             'Major version older; Minor version identical; Patch version newer' => [
761                 [
762                     ['TestLibrary', 'Test', 1, 1, 2],
763                 ],
764                 [
765                     'machineName' => 'TestLibrary',
766                     'majorVersion' => 0,
767                     'minorVersion' => 1,
768                     'patchVersion' => 3
769                 ],
770                 false,
771             ],
772         ];
773     }
775     /**
776      * Test the behaviour of isInDevMode().
777      */
778     public function test_isInDevMode() {
779         $isdevmode = $this->framework->isInDevMode();
781         $this->assertFalse($isdevmode);
782     }
784     /**
785      * Test the behaviour of mayUpdateLibraries().
786      */
787     public function test_mayUpdateLibraries(): void {
788         global $DB;
790         $this->resetAfterTest();
792         // Create some users.
793         $contextsys = \context_system::instance();
794         $user = $this->getDataGenerator()->create_user();
795         $admin = get_admin();
796         $managerrole = $DB->get_record('role', ['shortname' => 'manager'], '*', MUST_EXIST);
797         $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
798         $manager = $this->getDataGenerator()->create_user();
799         role_assign($managerrole->id, $manager->id, $contextsys);
801         // Create a course with a label and enrol the user.
802         $course = $this->getDataGenerator()->create_course();
803         $label = $this->getDataGenerator()->create_module('label', ['course' => $course->id]);
804         list(, $labelcm) = get_course_and_cm_from_instance($label->id, 'label');
805         $contextlabel = \context_module::instance($labelcm->id);
806         $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
808         // Create the .h5p file.
809         $path = __DIR__ . '/fixtures/h5ptest.zip';
811         // Admin and manager should have permission to update libraries.
812         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextsys);
813         $this->framework->set_file($file);
814         $mayupdatelib = $this->framework->mayUpdateLibraries();
815         $this->assertTrue($mayupdatelib);
817         $file = helper::create_fake_stored_file_from_path($path, $manager->id, $contextsys);
818         $this->framework->set_file($file);
819         $mayupdatelib = $this->framework->mayUpdateLibraries();
820         $this->assertTrue($mayupdatelib);
822         // By default, normal user hasn't permission to update libraries (in both contexts, system and module label).
823         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
824         $this->framework->set_file($file);
825         $mayupdatelib = $this->framework->mayUpdateLibraries();
826         $this->assertFalse($mayupdatelib);
828         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
829         $this->framework->set_file($file);
830         $mayupdatelib = $this->framework->mayUpdateLibraries();
831         $this->assertFalse($mayupdatelib);
833         // If the current user (admin) can update libraries, the method should return true (even if the file userid hasn't the
834         // required capabilility in the file context).
835         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextlabel);
836         $this->framework->set_file($file);
837         $mayupdatelib = $this->framework->mayUpdateLibraries();
838         $this->assertTrue($mayupdatelib);
840         // If the update capability is assigned to the user, they should be able to update the libraries (only in the context
841         // where the capability has been assigned).
842         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
843         $this->framework->set_file($file);
844         $mayupdatelib = $this->framework->mayUpdateLibraries();
845         $this->assertFalse($mayupdatelib);
846         assign_capability('moodle/h5p:updatelibraries', CAP_ALLOW, $studentrole->id, $contextlabel);
847         $mayupdatelib = $this->framework->mayUpdateLibraries();
848         $this->assertTrue($mayupdatelib);
849         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
850         $this->framework->set_file($file);
851         $mayupdatelib = $this->framework->mayUpdateLibraries();
852         $this->assertFalse($mayupdatelib);
853     }
855     /**
856      * Test the behaviour of get_file() and set_file().
857      */
858     public function test_get_file(): void {
859         $this->resetAfterTest();
861         // Create some users.
862         $contextsys = \context_system::instance();
863         $user = $this->getDataGenerator()->create_user();
865         // The H5P file.
866         $path = __DIR__ . '/fixtures/h5ptest.zip';
868         // An error should be raised when it's called before initialitzing it.
869         $this->expectException('coding_exception');
870         $this->expectExceptionMessage('Using get_file() before file is set');
871         $this->framework->get_file();
873         // Check the value when only path and user are set.
874         $file = helper::create_fake_stored_file_from_path($path, $user->id);
875         $this->framework->set_file($file);
876         $file = $this->framework->get_file();
877         $this->assertEquals($user->id, $$file->get_userid());
878         $this->assertEquals($contextsys->id, $file->get_contextid());
880         // Check the value when also the context is set.
881         $course = $this->getDataGenerator()->create_course();
882         $contextcourse = \context_course::instance($course->id);
883         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextcourse);
884         $this->framework->set_file($file);
885         $file = $this->framework->get_file();
886         $this->assertEquals($user->id, $$file->get_userid());
887         $this->assertEquals($contextcourse->id, $file->get_contextid());
888     }
890     /**
891      * Test the behaviour of saveLibraryData() when saving data for a new library.
892      */
893     public function test_saveLibraryData_new_library() {
894         global $DB;
896         $this->resetAfterTest();
898         $librarydata = array(
899             'title' => 'Test',
900             'machineName' => 'TestLibrary',
901             'majorVersion' => '1',
902             'minorVersion' => '0',
903             'patchVersion' => '2',
904             'runnable' => 1,
905             'fullscreen' => 1,
906             'preloadedJs' => array(
907                 array(
908                     'path' => 'js/name.min.js'
909                 )
910             ),
911             'preloadedCss' => array(
912                 array(
913                     'path' => 'css/name.css'
914                 )
915             ),
916             'dropLibraryCss' => array(
917                 array(
918                     'machineName' => 'Name2'
919                 )
920             )
921         );
923         // Create a new library.
924         $this->framework->saveLibraryData($librarydata);
926         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
928         // Make sure the library data was properly saved.
929         $this->assertNotEmpty($library);
930         $this->assertNotEmpty($librarydata['libraryId']);
931         $this->assertEquals($librarydata['title'], $library->title);
932         $this->assertEquals($librarydata['machineName'], $library->machinename);
933         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
934         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
935         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
936         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
937         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
938         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
939     }
941     /**
942      * Test the behaviour of saveLibraryData() when saving (updating) data for an existing library.
943      */
944     public function test_saveLibraryData_existing_library() {
945         global $DB;
947         $this->resetAfterTest();
949         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
951         // Create a library record.
952         $library = $generator->create_library_record('TestLibrary', 'Test', 1, 0, 2);
954         $librarydata = array(
955             'libraryId' => $library->id,
956             'title' => 'Test1',
957             'machineName' => 'TestLibrary',
958             'majorVersion' => '1',
959             'minorVersion' => '2',
960             'patchVersion' => '2',
961             'runnable' => 1,
962             'fullscreen' => 1,
963             'preloadedJs' => array(
964                 array(
965                     'path' => 'js/name.min.js'
966                 )
967             ),
968             'preloadedCss' => array(
969                 array(
970                     'path' => 'css/name.css'
971                 )
972             ),
973             'dropLibraryCss' => array(
974                 array(
975                     'machineName' => 'Name2'
976                 )
977             )
978         );
980         // Update the library.
981         $this->framework->saveLibraryData($librarydata, false);
983         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
985         // Make sure the library data was properly updated.
986         $this->assertNotEmpty($library);
987         $this->assertNotEmpty($librarydata['libraryId']);
988         $this->assertEquals($librarydata['title'], $library->title);
989         $this->assertEquals($librarydata['machineName'], $library->machinename);
990         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
991         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
992         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
993         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
994         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
995         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
996     }
998     /**
999      * Test the behaviour of insertContent().
1000      */
1001     public function test_insertContent() {
1002         global $DB;
1004         $this->resetAfterTest();
1006         $content = array(
1007             'params' => json_encode(['param1' => 'Test']),
1008             'library' => array(
1009                 'libraryId' => 1
1010             ),
1011             'disable' => 8
1012         );
1014         // Insert h5p content.
1015         $contentid = $this->framework->insertContent($content);
1017         // Get the entered content from the db.
1018         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1020         // Make sure the h5p content was properly inserted.
1021         $this->assertNotEmpty($dbcontent);
1022         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1023         $this->assertEquals($content['library']['libraryId'], $dbcontent->mainlibraryid);
1024         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1025     }
1027     /**
1028      * Test the behaviour of insertContent().
1029      */
1030     public function test_insertContent_latestlibrary() {
1031         global $DB;
1033         $this->resetAfterTest();
1035         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1036         // Create a library record.
1037         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1039         $content = array(
1040             'params' => json_encode(['param1' => 'Test']),
1041             'library' => array(
1042                 'libraryId' => 0,
1043                 'machineName' => 'TestLibrary',
1044             ),
1045             'disable' => 8
1046         );
1048         // Insert h5p content.
1049         $contentid = $this->framework->insertContent($content);
1051         // Get the entered content from the db.
1052         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1054         // Make sure the h5p content was properly inserted.
1055         $this->assertNotEmpty($dbcontent);
1056         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1057         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1058         // As the libraryId was empty, the latest library has been used.
1059         $this->assertEquals($lib->id, $dbcontent->mainlibraryid);
1060     }
1062     /**
1063      * Test the behaviour of updateContent().
1064      */
1065     public function test_updateContent() {
1066         global $DB;
1068         $this->resetAfterTest();
1070         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1072         // Create a library record.
1073         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1075         // Create an h5p content with 'TestLibrary' as it's main library.
1076         $contentid = $generator->create_h5p_record($lib->id);
1078         $content = array(
1079             'id' => $contentid,
1080             'params' => json_encode(['param2' => 'Test2']),
1081             'library' => array(
1082                 'libraryId' => $lib->id
1083             ),
1084             'disable' => 8
1085         );
1087         // Update the h5p content.
1088         $this->framework->updateContent($content);
1090         $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]);
1092         // Make sure the h5p content was properly updated.
1093         $this->assertNotEmpty($h5pcontent);
1094         $this->assertEquals($content['params'], $h5pcontent->jsoncontent);
1095         $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid);
1096         $this->assertEquals($content['disable'], $h5pcontent->displayoptions);
1097     }
1099     /**
1100      * Test the behaviour of saveLibraryDependencies().
1101      */
1102     public function test_saveLibraryDependencies() {
1103         global $DB;
1105         $this->resetAfterTest();
1107         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1109         // Create a library 'Library'.
1110         $library = $generator->create_library_record('Library', 'Title');
1111         // Create a library 'DependencyLibrary1'.
1112         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1113         // Create a library 'DependencyLibrary2'.
1114         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1116         $dependencies = array(
1117             array(
1118                 'machineName' => $dependency1->machinename,
1119                 'majorVersion' => $dependency1->majorversion,
1120                 'minorVersion' => $dependency1->minorversion
1121             ),
1122             array(
1123                 'machineName' => $dependency2->machinename,
1124                 'majorVersion' => $dependency2->majorversion,
1125                 'minorVersion' => $dependency2->minorversion
1126             ),
1127         );
1129         // Set 'DependencyLibrary1' and 'DependencyLibrary2' as library dependencies of 'Library'.
1130         $this->framework->saveLibraryDependencies($library->id, $dependencies, 'preloaded');
1132         $libdependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library->id], 'id ASC');
1134         // Make sure the library dependencies for 'Library' are properly set.
1135         $this->assertEquals(2, count($libdependencies));
1136         $this->assertEquals($dependency1->id, reset($libdependencies)->requiredlibraryid);
1137         $this->assertEquals($dependency2->id, end($libdependencies)->requiredlibraryid);
1138     }
1140     /**
1141      * Test the behaviour of deleteContentData().
1142      */
1143     public function test_deleteContentData() {
1144         global $DB;
1146         $this->resetAfterTest();
1148         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1150         // Generate some h5p related data.
1151         $data = $generator->generate_h5p_data();
1152         $h5pid = $data->h5pcontent->h5pid;
1154         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1155         // Make sure the particular h5p content exists in the DB.
1156         $this->assertNotEmpty($h5pcontent);
1158         // Get the h5p content libraries from the DB.
1159         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1161         // Make sure the content libraries exists in the DB.
1162         $this->assertNotEmpty($h5pcontentlibraries);
1163         $this->assertCount(5, $h5pcontentlibraries);
1165         // Delete the h5p content and it's related data.
1166         $this->framework->deleteContentData($h5pid);
1168         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1169         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1171         // The particular h5p content should no longer exist in the db.
1172         $this->assertEmpty($h5pcontent);
1173         // The particular content libraries should no longer exist in the db.
1174         $this->assertEmpty($h5pcontentlibraries);
1175     }
1177     /**
1178      * Test the behaviour of deleteLibraryUsage().
1179      */
1180     public function test_deleteLibraryUsage() {
1181         global $DB;
1183         $this->resetAfterTest();
1185         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1187         // Generate some h5p related data.
1188         $data = $generator->generate_h5p_data();
1189         $h5pid = $data->h5pcontent->h5pid;
1191         // Get the h5p content libraries from the DB.
1192         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1194         // The particular h5p content should have 5 content libraries.
1195         $this->assertNotEmpty($h5pcontentlibraries);
1196         $this->assertCount(5, $h5pcontentlibraries);
1198         // Delete the h5p content and it's related data.
1199         $this->framework->deleteLibraryUsage($h5pid);
1201         // Get the h5p content libraries from the DB.
1202         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1204         // The particular h5p content libraries should no longer exist in the db.
1205         $this->assertEmpty($h5pcontentlibraries);
1206     }
1208     /**
1209      * Test the behaviour of test_saveLibraryUsage().
1210      */
1211     public function test_saveLibraryUsage() {
1212         global $DB;
1214         $this->resetAfterTest();
1216         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1218         // Create a library 'Library'.
1219         $library = $generator->create_library_record('Library', 'Title');
1220         // Create a library 'DependencyLibrary1'.
1221         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1222         // Create a library 'DependencyLibrary2'.
1223         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1224         // Create an h5p content with 'Library' as it's main library.
1225         $contentid = $generator->create_h5p_record($library->id);
1227         $dependencies = array(
1228             array(
1229                 'library' => array(
1230                     'libraryId' => $dependency1->id,
1231                     'machineName' => $dependency1->machinename,
1232                     'dropLibraryCss' => $dependency1->droplibrarycss
1233                 ),
1234                 'type' => 'preloaded',
1235                 'weight' => 1
1236             ),
1237             array(
1238                 'library' => array(
1239                     'libraryId' => $dependency2->id,
1240                     'machineName' => $dependency2->machinename,
1241                     'dropLibraryCss' => $dependency2->droplibrarycss
1242                 ),
1243                 'type' => 'preloaded',
1244                 'weight' => 2
1245             ),
1246         );
1248         // Save 'DependencyLibrary1' and 'DependencyLibrary2' as h5p content libraries.
1249         $this->framework->saveLibraryUsage($contentid, $dependencies);
1251         // Get the h5p content libraries from the DB.
1252         $libdependencies = $DB->get_records('h5p_contents_libraries', ['h5pid' => $contentid], 'id ASC');
1254         // Make sure that 'DependencyLibrary1' and 'DependencyLibrary2' are properly set as h5p content libraries.
1255         $this->assertEquals(2, count($libdependencies));
1256         $this->assertEquals($dependency1->id, reset($libdependencies)->libraryid);
1257         $this->assertEquals($dependency2->id, end($libdependencies)->libraryid);
1258     }
1260     /**
1261      * Test the behaviour of getLibraryUsage() without skipping a particular h5p content.
1262      */
1263     public function test_getLibraryUsage_no_skip_content() {
1264         $this->resetAfterTest();
1266         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1268         // Generate h5p related data.
1269         $generateddata = $generator->generate_h5p_data();
1270         // The Id of the library 'Library1'.
1271         $library1id = $generateddata->lib1->data->id;
1272         // The Id of the library 'Library2'.
1273         $library2id = $generateddata->lib2->data->id;
1274         // The Id of the library 'Library5'.
1275         $library5id = $generateddata->lib5->data->id;
1277         // Get the library usage for 'Library1' (do not skip content).
1278         $data = $this->framework->getLibraryUsage($library1id);
1280         $expected = array(
1281             'content' => 1,
1282             'libraries' => 1
1283         );
1285         // Make sure 'Library1' is used by 1 content and is a dependency to 1 library.
1286         $this->assertEquals($expected, $data);
1288         // Get the library usage for 'Library2' (do not skip content).
1289         $data = $this->framework->getLibraryUsage($library2id);
1291         $expected = array(
1292             'content' => 1,
1293             'libraries' => 2,
1294         );
1296         // Make sure 'Library2' is used by 1 content and is a dependency to 2 libraries.
1297         $this->assertEquals($expected, $data);
1299          // Get the library usage for 'Library5' (do not skip content).
1300         $data = $this->framework->getLibraryUsage($library5id);
1302         $expected = array(
1303             'content' => 0,
1304             'libraries' => 1,
1305         );
1307         // Make sure 'Library5' is not used by any content and is a dependency to 1 library.
1308         $this->assertEquals($expected, $data);
1309     }
1311     /**
1312      * Test the behaviour of getLibraryUsage() when skipping a particular content.
1313      */
1314     public function test_getLibraryUsage_skip_content() {
1315         $this->resetAfterTest();
1317         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1319         // Generate h5p related data.
1320         $generateddata = $generator->generate_h5p_data();
1321         // The Id of the library 'Library1'.
1322         $library1id = $generateddata->lib1->data->id;
1324         // Get the library usage for 'Library1' (skip content).
1325         $data = $this->framework->getLibraryUsage($library1id, true);
1326         $expected = array(
1327             'content' => -1,
1328             'libraries' => 1,
1329         );
1331         // Make sure 'Library1' is a dependency to 1 library.
1332         $this->assertEquals($expected, $data);
1333     }
1335     /**
1336      * Test the behaviour of loadLibrary() when requesting an existing library.
1337      */
1338     public function test_loadLibrary_existing_library() {
1339         $this->resetAfterTest();
1341         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1343         // Generate h5p related data.
1344         $generateddata = $generator->generate_h5p_data();
1345         // The library data of 'Library1'.
1346         $library1 = $generateddata->lib1->data;
1347         // The library data of 'Library5'.
1348         $library5 = $generateddata->lib5->data;
1350         // The preloaded dependencies.
1351         $preloadeddependencies = array();
1353         foreach ($generateddata->lib1->dependencies as $preloadeddependency) {
1354             $preloadeddependencies[] = array(
1355                 'machineName' => $preloadeddependency->machinename,
1356                 'majorVersion' => $preloadeddependency->majorversion,
1357                 'minorVersion' => $preloadeddependency->minorversion
1358             );
1359         }
1361         // Create a dynamic dependency.
1362         $generator->create_library_dependency_record($library1->id, $library5->id, 'dynamic');
1364         $dynamicdependencies[] = array(
1365             'machineName' => $library5->machinename,
1366             'majorVersion' => $library5->majorversion,
1367             'minorVersion' => $library5->minorversion
1368         );
1370         // Load 'Library1' data.
1371         $data = $this->framework->loadLibrary($library1->machinename, $library1->majorversion,
1372             $library1->minorversion);
1374         $expected = array(
1375             'libraryId' => $library1->id,
1376             'title' => $library1->title,
1377             'machineName' => $library1->machinename,
1378             'majorVersion' => $library1->majorversion,
1379             'minorVersion' => $library1->minorversion,
1380             'patchVersion' => $library1->patchversion,
1381             'runnable' => $library1->runnable,
1382             'fullscreen' => $library1->fullscreen,
1383             'embedTypes' => $library1->embedtypes,
1384             'preloadedJs' => $library1->preloadedjs,
1385             'preloadedCss' => $library1->preloadedcss,
1386             'dropLibraryCss' => $library1->droplibrarycss,
1387             'semantics' => $library1->semantics,
1388             'preloadedDependencies' => $preloadeddependencies,
1389             'dynamicDependencies' => $dynamicdependencies
1390         );
1392         // Make sure the 'Library1' data is properly loaded.
1393         $this->assertEquals($expected, $data);
1394     }
1396     /**
1397      * Test the behaviour of loadLibrary() when requesting a non-existent library.
1398      */
1399     public function test_loadLibrary_non_existent_library() {
1400         $this->resetAfterTest();
1402         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1404         // Generate h5p related data.
1405         $generator->generate_h5p_data();
1407         // Attempt to load a non-existent library.
1408         $data = $this->framework->loadLibrary('MissingLibrary', 1, 2);
1410         // Make sure nothing is loaded.
1411         $this->assertFalse($data);
1412     }
1414     /**
1415      * Test the behaviour of loadLibrarySemantics().
1416      *
1417      * @dataProvider test_loadLibrarySemantics_provider
1418      * @param array $libraryrecords Array containing data for the library creation
1419      * @param array $testlibrary Array containing the test library data
1420      * @param string $expected The expected semantics value
1421      **/
1422     public function test_loadLibrarySemantics(array $libraryrecords, array $testlibrary, string $expected): void {
1423         $this->resetAfterTest();
1425         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1427         foreach ($libraryrecords as $library) {
1428             call_user_func_array([$generator, 'create_library_record'], $library);
1429         }
1431         $this->assertEquals($expected, $this->framework->loadLibrarySemantics(
1432             $testlibrary['machinename'], $testlibrary['majorversion'], $testlibrary['minorversion']));
1433     }
1435     /**
1436      * Data provider for test_loadLibrarySemantics().
1437      *
1438      * @return array
1439      */
1440     public function test_loadLibrarySemantics_provider(): array {
1442         $semantics = json_encode(
1443             [
1444                 'type' => 'text',
1445                 'name' => 'text',
1446                 'label' => 'Plain text',
1447                 'description' => 'Please add some text'
1448             ]
1449         );
1451         return [
1452             'Library with semantics' => [
1453                 [
1454                     ['Library1', 'Lib1', 1, 1, 2, $semantics],
1455                 ],
1456                 [
1457                     'machinename' => 'Library1',
1458                     'majorversion' => 1,
1459                     'minorversion' => 1
1460                 ],
1461                 $semantics,
1462             ],
1463             'Library without semantics' => [
1464                 [
1465                     ['Library2', 'Lib2', 1, 2, 2, ''],
1466                 ],
1467                 [
1468                     'machinename' => 'Library2',
1469                     'majorversion' => 1,
1470                     'minorversion' => 2
1471                 ],
1472                 '',
1473             ]
1474         ];
1475     }
1477     /**
1478      * Test the behaviour of alterLibrarySemantics().
1479      */
1480     public function test_alterLibrarySemantics() {
1481         global $DB;
1483         $this->resetAfterTest();
1485         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1487         $semantics = json_encode(
1488             array(
1489                 'type' => 'text',
1490                 'name' => 'text',
1491                 'label' => 'Plain text',
1492                 'description' => 'Please add some text'
1493             )
1494         );
1496         // Create a library 'Library1' with semantics.
1497         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2, $semantics);
1499         $updatedsemantics = array(
1500             'type' => 'text',
1501             'name' => 'updated text',
1502             'label' => 'Updated text',
1503             'description' => 'Please add some text'
1504         );
1506         // Alter the semantics of 'Library1'.
1507         $this->framework->alterLibrarySemantics($updatedsemantics, 'Library1', 1, 1);
1509         // Get the semantics of 'Library1' from the DB.
1510         $currentsemantics = $DB->get_field('h5p_libraries', 'semantics', array('id' => $library1->id));
1512         // The semantics for Library1 shouldn't be updated.
1513         $this->assertEquals($semantics, $currentsemantics);
1514     }
1516     /**
1517      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1518      * dependencies of an existing library.
1519      */
1520     public function test_deleteLibraryDependencies_existing_library() {
1521         global $DB;
1523         $this->resetAfterTest();
1525         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1527         // Generate h5p related data.
1528         $data = $generator->generate_h5p_data();
1529         // The data of the library 'Library1'.
1530         $library1 = $data->lib1->data;
1532         // Get the dependencies of 'Library1'.
1533         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1534         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1535         $this->assertCount(3, $dependencies);
1537         // Delete the dependencies of 'Library1'.
1538         $this->framework->deleteLibraryDependencies($library1->id);
1540         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1541         // The 'Library1' should have 0 dependencies.
1542         $this->assertCount(0, $dependencies);
1543     }
1545     /**
1546      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1547      * dependencies of a non-existent library.
1548      */
1549     public function test_deleteLibraryDependencies_non_existent_library() {
1550         global $DB;
1552         $this->resetAfterTest();
1554         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1556         // Generate h5p related data.
1557         $data = $generator->generate_h5p_data();
1558         // The data of the library 'Library1'.
1559         $library1 = $data->lib1->data;
1561         // Get the dependencies of 'Library1'.
1562         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1563         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1564         $this->assertCount(3, $dependencies);
1566         // Delete the dependencies of a non-existent library.
1567         $this->framework->deleteLibraryDependencies(0);
1569         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1570         // The 'Library1' should have 3 dependencies.
1571         $this->assertCount(3, $dependencies);
1572     }
1574     /**
1575      * Test the behaviour of deleteLibrary().
1576      */
1577     public function test_deleteLibrary() {
1578         global $DB;
1580         $this->resetAfterTest();
1582         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1584         // Generate h5p related data.
1585         $data = $generator->generate_h5p_data(true);
1586         // The data of the 'Library1' library.
1587         $library1 = $data->lib1->data;
1589         // Get the library dependencies of 'Library1'.
1590         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1592         // The 'Library1' should have 3 library dependencies ('Library2', 'Library3', 'Library4').
1593         $this->assertCount(3, $dependencies);
1595         // Return the created 'Library1' files.
1596         $libraryfiles = $DB->get_records('files',
1597             array(
1598                 'component' => \core_h5p\file_storage::COMPONENT,
1599                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1600                 'itemid' => $library1->id
1601             )
1602         );
1604         // The library ('Library1') should have 7 related folders/files.
1605         $this->assertCount(7, $libraryfiles);
1607         // Delete the library.
1608         $this->framework->deleteLibrary($library1);
1610         $lib1 = $DB->get_record('h5p_libraries', ['machinename' => $library1->machinename]);
1611         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1612         $libraryfiles = $DB->get_records('files',
1613             array(
1614                 'component' => \core_h5p\file_storage::COMPONENT,
1615                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1616                 'itemid' => $library1->id
1617             )
1618         );
1620         // The 'Library1' should not exist.
1621         $this->assertEmpty($lib1);
1622         // The library ('Library1')  should have 0 dependencies.
1623         $this->assertCount(0, $dependencies);
1624         // The library (library1) should have 0 related folders/files.
1625         $this->assertCount(0, $libraryfiles);
1626     }
1628     /**
1629      * Test the behaviour of loadContent().
1630      */
1631     public function test_loadContent() {
1632         global $DB;
1634         $this->resetAfterTest();
1636         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1638         // Generate h5p related data.
1639         $data = $generator->generate_h5p_data();
1640         // The Id of the created h5p content.
1641         $h5pid = $data->h5pcontent->h5pid;
1642         // Get the h5p content data from the DB.
1643         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1644         // The data of content's main library ('MainLibrary').
1645         $mainlibrary = $data->mainlib->data;
1647         // Load the h5p content.
1648         $content = $this->framework->loadContent($h5pid);
1650         $expected = array(
1651             'id' => $h5p->id,
1652             'params' => $h5p->jsoncontent,
1653             'embedType' => 'iframe',
1654             'disable' => $h5p->displayoptions,
1655             'title' => $mainlibrary->title,
1656             'slug' => \H5PCore::slugify($mainlibrary->title) . '-' . $h5p->id,
1657             'filtered' => $h5p->filtered,
1658             'libraryId' => $mainlibrary->id,
1659             'libraryName' => $mainlibrary->machinename,
1660             'libraryMajorVersion' => $mainlibrary->majorversion,
1661             'libraryMinorVersion' => $mainlibrary->minorversion,
1662             'libraryEmbedTypes' => $mainlibrary->embedtypes,
1663             'libraryFullscreen' => $mainlibrary->fullscreen,
1664             'metadata' => '',
1665             'pathnamehash' => $h5p->pathnamehash
1666         );
1668         $params = json_decode($h5p->jsoncontent);
1669         if (empty($params->metadata)) {
1670             $params->metadata = new \stdClass();
1671         }
1672         $expected['metadata'] = $params->metadata;
1673         $expected['params'] = json_encode($params->params ?? $params);
1675         // The returned content should match the expected array.
1676         $this->assertEquals($expected, $content);
1677     }
1679     /**
1680      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1681      * without specifying the dependency type.
1682      */
1683     public function test_loadContentDependencies_no_type_defined() {
1684         $this->resetAfterTest();
1686         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1688         // Generate h5p related data.
1689         $data = $generator->generate_h5p_data();
1690         // The Id of the h5p content.
1691         $h5pid = $data->h5pcontent->h5pid;
1692         // The content dependencies.
1693         $dependencies = $data->h5pcontent->contentdependencies;
1695         // Add Library5 as a content dependency (dynamic dependency type).
1696         $library5 = $data->lib5->data;
1697         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1699         // Get all content dependencies.
1700         $contentdependencies = $this->framework->loadContentDependencies($h5pid);
1702         $expected = array();
1703         foreach ($dependencies as $dependency) {
1704             $expected[$dependency->machinename] = array(
1705                 'libraryId' => $dependency->id,
1706                 'machineName' => $dependency->machinename,
1707                 'majorVersion' => $dependency->majorversion,
1708                 'minorVersion' => $dependency->minorversion,
1709                 'patchVersion' => $dependency->patchversion,
1710                 'preloadedCss' => $dependency->preloadedcss,
1711                 'preloadedJs' => $dependency->preloadedjs,
1712                 'dropCss' => '0',
1713                 'dependencyType' => 'preloaded'
1714             );
1715         }
1717         $expected = array_merge($expected,
1718             array(
1719                 'Library5' => array(
1720                     'libraryId' => $library5->id,
1721                     'machineName' => $library5->machinename,
1722                     'majorVersion' => $library5->majorversion,
1723                     'minorVersion' => $library5->minorversion,
1724                     'patchVersion' => $library5->patchversion,
1725                     'preloadedCss' => $library5->preloadedcss,
1726                     'preloadedJs' => $library5->preloadedjs,
1727                     'dropCss' => '0',
1728                     'dependencyType' => 'dynamic'
1729                 )
1730             )
1731         );
1733         // The loaded content dependencies should return 6 libraries.
1734         $this->assertCount(6, $contentdependencies);
1735         $this->assertEquals($expected, $contentdependencies);
1736     }
1738     /**
1739      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1740      * with specifying the dependency type.
1741      */
1742     public function test_loadContentDependencies_type_defined() {
1743         $this->resetAfterTest();
1745         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1747         // Generate h5p related data.
1748         $data = $generator->generate_h5p_data();
1749         // The Id of the h5p content.
1750         $h5pid = $data->h5pcontent->h5pid;
1751         // The content dependencies.
1752         $dependencies = $data->h5pcontent->contentdependencies;
1754         // Add Library5 as a content dependency (dynamic dependency type).
1755         $library5 = $data->lib5->data;
1756         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1758         // Load all content dependencies of dependency type 'preloaded'.
1759         $preloadeddependencies = $this->framework->loadContentDependencies($h5pid, 'preloaded');
1761         $expected = array();
1762         foreach ($dependencies as $dependency) {
1763             $expected[$dependency->machinename] = array(
1764                 'libraryId' => $dependency->id,
1765                 'machineName' => $dependency->machinename,
1766                 'majorVersion' => $dependency->majorversion,
1767                 'minorVersion' => $dependency->minorversion,
1768                 'patchVersion' => $dependency->patchversion,
1769                 'preloadedCss' => $dependency->preloadedcss,
1770                 'preloadedJs' => $dependency->preloadedjs,
1771                 'dropCss' => '0',
1772                 'dependencyType' => 'preloaded'
1773             );
1774         }
1776         // The loaded content dependencies should return 5 libraries.
1777         $this->assertCount(5, $preloadeddependencies);
1778         $this->assertEquals($expected, $preloadeddependencies);
1780         // Load all content dependencies of dependency type 'dynamic'.
1781         $dynamicdependencies = $this->framework->loadContentDependencies($h5pid, 'dynamic');
1783         $expected = array(
1784             'Library5' => array(
1785                 'libraryId' => $library5->id,
1786                 'machineName' => $library5->machinename,
1787                 'majorVersion' => $library5->majorversion,
1788                 'minorVersion' => $library5->minorversion,
1789                 'patchVersion' => $library5->patchversion,
1790                 'preloadedCss' => $library5->preloadedcss,
1791                 'preloadedJs' => $library5->preloadedjs,
1792                 'dropCss' => '0',
1793                 'dependencyType' => 'dynamic'
1794             )
1795         );
1797         // The loaded content dependencies should now return 1 library.
1798         $this->assertCount(1, $dynamicdependencies);
1799         $this->assertEquals($expected, $dynamicdependencies);
1800     }
1802     /**
1803      * Test the behaviour of getOption().
1804      */
1805     public function test_getOption(): void {
1806         $this->resetAfterTest();
1808         // Get value for display_option_download.
1809         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_DOWNLOAD);
1810         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1811         $this->assertEquals($expected, $value);
1813         // Get value for display_option_embed using default value (it should be ignored).
1814         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_EMBED, \H5PDisplayOptionBehaviour::NEVER_SHOW);
1815         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1816         $this->assertEquals($expected, $value);
1818         // Get value for unexisting setting without default.
1819         $value = $this->framework->getOption('unexistingsetting');
1820         $expected = false;
1821         $this->assertEquals($expected, $value);
1823         // Get value for unexisting setting with default.
1824         $value = $this->framework->getOption('unexistingsetting', 'defaultvalue');
1825         $expected = 'defaultvalue';
1826         $this->assertEquals($expected, $value);
1827     }
1829     /**
1830      * Test the behaviour of setOption().
1831      */
1832     public function test_setOption(): void {
1833         $this->resetAfterTest();
1835         // Set value for 'newsetting' setting.
1836         $name = 'newsetting';
1837         $value = $this->framework->getOption($name);
1838         $this->assertEquals(false, $value);
1839         $newvalue = 'value1';
1840         $this->framework->setOption($name, $newvalue);
1841         $value = $this->framework->getOption($name);
1842         $this->assertEquals($newvalue, $value);
1844         // Set value for display_option_download and then get it again. Check it hasn't changed.
1845         $name = \H5PCore::DISPLAY_OPTION_DOWNLOAD;
1846         $newvalue = \H5PDisplayOptionBehaviour::NEVER_SHOW;
1847         $this->framework->setOption($name, $newvalue);
1848         $value = $this->framework->getOption($name);
1849         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1850         $this->assertEquals($expected, $value);
1851     }
1853     /**
1854      * Test the behaviour of updateContentFields().
1855      */
1856     public function test_updateContentFields() {
1857         global $DB;
1859         $this->resetAfterTest();
1861         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1863         // Create 'Library1' library.
1864         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1865         // Create 'Library2' library.
1866         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1868         // Create an h5p content with 'Library1' as it's main library.
1869         $h5pid = $generator->create_h5p_record($library1->id, 'iframe');
1871         $updatedata = array(
1872             'jsoncontent' => json_encode(['value' => 'test']),
1873             'mainlibraryid' => $library2->id
1874         );
1876         // Update h5p content fields.
1877         $this->framework->updateContentFields($h5pid, $updatedata);
1879         // Get the h5p content from the DB.
1880         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1882         $expected = json_encode(['value' => 'test']);
1884         // Make sure the h5p content fields are properly updated.
1885         $this->assertEquals($expected, $h5p->jsoncontent);
1886         $this->assertEquals($library2->id, $h5p->mainlibraryid);
1887     }
1889     /**
1890      * Test the behaviour of clearFilteredParameters().
1891      */
1892     public function test_clearFilteredParameters() {
1893         global $DB;
1895         $this->resetAfterTest();
1897         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1899         // Create 3 libraries.
1900         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1901         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1902         $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1904         // Create h5p content with 'Library1' as a main library.
1905         $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1906         // Create h5p content with 'Library1' as a main library.
1907         $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1908         // Create h5p content with 'Library2' as a main library.
1909         $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1910         // Create h5p content with 'Library3' as a main library.
1911         $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1913         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1914         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1915         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1916         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1918         // The filtered parameters should be present in each h5p content.
1919         $this->assertNotEmpty($h5pcontent1->filtered);
1920         $this->assertNotEmpty($h5pcontent2->filtered);
1921         $this->assertNotEmpty($h5pcontent3->filtered);
1922         $this->assertNotEmpty($h5pcontent4->filtered);
1924         // Clear the filtered parameters for contents that have library1 and library3 as
1925         // their main library.
1926         $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1928         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1929         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1930         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1931         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1933         // The filtered parameters should be still present only for the content that has
1934         // library 2 as a main library.
1935         $this->assertEmpty($h5pcontent1->filtered);
1936         $this->assertEmpty($h5pcontent2->filtered);
1937         $this->assertNotEmpty($h5pcontent3->filtered);
1938         $this->assertEmpty($h5pcontent4->filtered);
1939     }
1941     /**
1942      * Test the behaviour of getNumNotFiltered().
1943      */
1944     public function test_getNumNotFiltered() {
1945         global $DB;
1947         $this->resetAfterTest();
1949         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1951         // Create 3 libraries.
1952         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1953         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1954         $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1956         // Create h5p content with library1 as a main library.
1957         $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1958         // Create h5p content with library1 as a main library.
1959         $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1960         // Create h5p content with library2 as a main library.
1961         $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1962         // Create h5p content with library3 as a main library.
1963         $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1965         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1966         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1967         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1968         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1970         // The filtered parameters should be present in each h5p content.
1971         $this->assertNotEmpty($h5pcontent1->filtered);
1972         $this->assertNotEmpty($h5pcontent2->filtered);
1973         $this->assertNotEmpty($h5pcontent3->filtered);
1974         $this->assertNotEmpty($h5pcontent4->filtered);
1976         // Clear the filtered parameters for contents that have library1 and library3 as
1977         // their main library.
1978         $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1980         $countnotfiltered = $this->framework->getNumNotFiltered();
1982         // 3 contents don't have their parameters filtered.
1983         $this->assertEquals(3, $countnotfiltered);
1984     }
1986     /**
1987      * Test the behaviour of getNumContent().
1988      */
1989     public function test_getNumContent() {
1990         $this->resetAfterTest();
1992         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1994         // Generate h5p related data.
1995         $data = $generator->generate_h5p_data();
1997         // The 'MainLibrary' library data.
1998         $mainlibrary = $data->mainlib->data;
2000         // The 'Library1' library data.
2001         $library1 = $data->lib1->data;
2003         // Create new h5p content with MainLibrary as a main library.
2004         $generator->create_h5p_record($mainlibrary->id);
2006         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
2007         $countmainlib = $this->framework->getNumContent($mainlibrary->id);
2009         // Get the number of h5p contents that are using 'Library1' as their main library.
2010         $countlib1 = $this->framework->getNumContent($library1->id);
2012         // Make sure that 2 contents are using MainLibrary as their main library.
2013         $this->assertEquals(2, $countmainlib);
2014         // Make sure that 0 contents are using Library1 as their main library.
2015         $this->assertEquals(0, $countlib1);
2016     }
2018     /**
2019      * Test the behaviour of getNumContent() when certain contents are being skipped.
2020      */
2021     public function test_getNumContent_skip_content() {
2022         $this->resetAfterTest();
2024         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2026         // Generate h5p related data.
2027         $data = $generator->generate_h5p_data();
2029         // The 'MainLibrary' library data.
2030         $mainlibrary = $data->mainlib->data;
2032         // Create new h5p content with MainLibrary as a main library.
2033         $h5pcontentid = $generator->create_h5p_record($mainlibrary->id);
2035         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
2036         // Skip the newly created content $h5pcontentid.
2037         $countmainlib = $this->framework->getNumContent($mainlibrary->id, [$h5pcontentid]);
2039         // Make sure that 1 content is returned instead of 2 ($h5pcontentid being skipped).
2040         $this->assertEquals(1, $countmainlib);
2041     }
2043     /**
2044      * Test the behaviour of isContentSlugAvailable().
2045      */
2046     public function test_isContentSlugAvailable() {
2047         $this->resetAfterTest();
2049         $slug = 'h5p-test-slug-1';
2051         // Currently this returns always true. The slug is generated as a unique value for
2052         // each h5p content and it is not stored in the h5p content table.
2053         $isslugavailable = $this->framework->isContentSlugAvailable($slug);
2055         $this->assertTrue($isslugavailable);
2056     }
2058     /**
2059      * Test that a record is stored for cached assets.
2060      */
2061     public function test_saveCachedAssets() {
2062         global $DB;
2064         $this->resetAfterTest();
2066         $libraries = array(
2067             array(
2068                 'machineName' => 'H5P.TestLib',
2069                 'libraryId' => 405,
2070             ),
2071             array(
2072                 'FontAwesome' => 'FontAwesome',
2073                 'libraryId' => 406,
2074             ),
2075             array(
2076                 'machineName' => 'H5P.SecondLib',
2077                 'libraryId' => 407,
2078             ),
2079         );
2081         $key = 'testhashkey';
2083         $this->framework->saveCachedAssets($key, $libraries);
2085         $records = $DB->get_records('h5p_libraries_cachedassets');
2087         $this->assertCount(3, $records);
2088     }
2090     /**
2091      * Test that the correct libraries are removed from the cached assets table
2092      */
2093     public function test_deleteCachedAssets() {
2094         global $DB;
2096         $this->resetAfterTest();
2098         $libraries = array(
2099             array(
2100                 'machineName' => 'H5P.TestLib',
2101                 'libraryId' => 405,
2102             ),
2103             array(
2104                 'FontAwesome' => 'FontAwesome',
2105                 'libraryId' => 406,
2106             ),
2107             array(
2108                 'machineName' => 'H5P.SecondLib',
2109                 'libraryId' => 407,
2110             ),
2111         );
2113         $key1 = 'testhashkey';
2114         $this->framework->saveCachedAssets($key1, $libraries);
2116         $libraries = array(
2117             array(
2118                 'machineName' => 'H5P.DiffLib',
2119                 'libraryId' => 408,
2120             ),
2121             array(
2122                 'FontAwesome' => 'FontAwesome',
2123                 'libraryId' => 406,
2124             ),
2125             array(
2126                 'machineName' => 'H5P.ThirdLib',
2127                 'libraryId' => 409,
2128             ),
2129         );
2131         $key2 = 'secondhashkey';
2132         $this->framework->saveCachedAssets($key2, $libraries);
2134         $libraries = array(
2135             array(
2136                 'machineName' => 'H5P.AnotherDiffLib',
2137                 'libraryId' => 410,
2138             ),
2139             array(
2140                 'FontAwesome' => 'NotRelated',
2141                 'libraryId' => 411,
2142             ),
2143             array(
2144                 'machineName' => 'H5P.ForthLib',
2145                 'libraryId' => 412,
2146             ),
2147         );
2149         $key3 = 'threeforthewin';
2150         $this->framework->saveCachedAssets($key3, $libraries);
2152         $records = $DB->get_records('h5p_libraries_cachedassets');
2153         $this->assertCount(9, $records);
2155         // Selecting one library id will result in all related library entries also being deleted.
2156         // Going to use the FontAwesome library id. The first two hashes should be returned.
2157         $hashes = $this->framework->deleteCachedAssets(406);
2158         $this->assertCount(2, $hashes);
2159         $index = array_search($key1, $hashes);
2160         $this->assertEquals($key1, $hashes[$index]);
2161         $index = array_search($key2, $hashes);
2162         $this->assertEquals($key2, $hashes[$index]);
2163         $index = array_search($key3, $hashes);
2164         $this->assertFalse($index);
2166         // Check that the records have been removed as well.
2167         $records = $DB->get_records('h5p_libraries_cachedassets');
2168         $this->assertCount(3, $records);
2169     }
2171     /**
2172      * Test the behaviour of getLibraryContentCount().
2173      */
2174     public function test_getLibraryContentCount() {
2175         $this->resetAfterTest();
2177         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2179         // Generate h5p related data.
2180         $data = $generator->generate_h5p_data();
2182         // The 'MainLibrary' library data.
2183         $mainlibrary = $data->mainlib->data;
2185         // The 'Library2' library data.
2186         $library2 = $data->lib2->data;
2188         // Create new h5p content with Library2 as it's main library.
2189         $generator->create_h5p_record($library2->id);
2191         // Create new h5p content with MainLibrary as it's main library.
2192         $generator->create_h5p_record($mainlibrary->id);
2194         $countlibrarycontent = $this->framework->getLibraryContentCount();
2196         $expected = array(
2197             "{$mainlibrary->machinename} {$mainlibrary->majorversion}.{$mainlibrary->minorversion}" => 2,
2198             "{$library2->machinename} {$library2->majorversion}.{$library2->minorversion}" => 1,
2199         );
2201         // MainLibrary and Library1 are currently main libraries to the existing h5p contents.
2202         // Should return the number of cases where MainLibrary and Library1 are main libraries to an h5p content.
2203         $this->assertEquals($expected, $countlibrarycontent);
2204     }
2206     /**
2207      * Test the behaviour of test_libraryHasUpgrade().
2208      *
2209      * @dataProvider test_libraryHasUpgrade_provider
2210      * @param array $libraryrecords Array containing data for the library creation
2211      * @param array $testlibrary Array containing the test library data
2212      * @param bool $expected The expectation whether the library is patched or not
2213      **/
2214     public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary, bool $expected): void {
2215         $this->resetAfterTest();
2217         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2219         foreach ($libraryrecords as $library) {
2220             call_user_func_array([$generator, 'create_library_record'], $library);
2221         }
2223         $this->assertEquals($expected, $this->framework->libraryHasUpgrade($testlibrary));
2224     }
2226     /**
2227      * Data provider for test_libraryHasUpgrade().
2228      *
2229      * @return array
2230      */
2231     public function test_libraryHasUpgrade_provider(): array {
2232         return [
2233             'Lower major version; Identical lower version' => [
2234                 [
2235                     ['Library', 'Lib', 2, 2],
2236                 ],
2237                 [
2238                     'machineName' => 'Library',
2239                     'majorVersion' => 1,
2240                     'minorVersion' => 2
2241                 ],
2242                 true,
2243             ],
2244             'Major version identical; Lower minor version' => [
2245                 [
2246                     ['Library', 'Lib', 2, 2],
2247                 ],
2248                 [
2249                     'machineName' => 'Library',
2250                     'majorVersion' => 2,
2251                     'minorVersion' => 1
2252                 ],
2253                 true,
2254             ],
2255             'Major version identical; Minor version identical' => [
2256                 [
2257                     ['Library', 'Lib', 2, 2],
2258                 ],
2259                 [
2260                     'machineName' => 'Library',
2261                     'majorVersion' => 2,
2262                     'minorVersion' => 2
2263                 ],
2264                 false,
2265             ],
2266             'Major version higher; Minor version identical' => [
2267                 [
2268                     ['Library', 'Lib', 2, 2],
2269                 ],
2270                 [
2271                     'machineName' => 'Library',
2272                     'majorVersion' => 3,
2273                     'minorVersion' => 2
2274                 ],
2275                 false,
2276             ],
2277             'Major version identical; Minor version newer' => [
2278                 [
2279                     ['Library', 'Lib', 2, 2],
2280                 ],
2281                 [
2282                     'machineName' => 'Library',
2283                     'majorVersion' => 2,
2284                     'minorVersion' => 4
2285                 ],
2286                 false,
2287             ]
2288         ];
2289     }
2292     /**
2293      * Test the behaviour of get_latest_library_version().
2294      */
2295     public function test_get_latest_library_version() {
2296         global $DB;
2298         $this->resetAfterTest();
2300         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2301         // Create a library record.
2302         $machinename = 'TestLibrary';
2303         $lib1 = $generator->create_library_record($machinename, 'Test', 1, 1, 2);
2304         $lib2 = $generator->create_library_record($machinename, 'Test', 1, 2, 1);
2306         $content = array(
2307             'params' => json_encode(['param1' => 'Test']),
2308             'library' => array(
2309                 'libraryId' => 0,
2310                 'machineName' => 'TestLibrary',
2311             ),
2312             'disable' => 8
2313         );
2315         // Get the latest id (at this point, should be lib2).
2316         $latestlib = $this->framework->get_latest_library_version($machinename);
2317         $this->assertEquals($lib2->id, $latestlib->id);
2319         // Get the latest id (at this point, should be lib3).
2320         $lib3 = $generator->create_library_record($machinename, 'Test', 2, 1, 0);
2321         $latestlib = $this->framework->get_latest_library_version($machinename);
2322         $this->assertEquals($lib3->id, $latestlib->id);
2324         // Get the latest id (at this point, should be still lib3).
2325         $lib4 = $generator->create_library_record($machinename, 'Test', 1, 1, 3);
2326         $latestlib = $this->framework->get_latest_library_version($machinename);
2327         $this->assertEquals($lib3->id, $latestlib->id);
2329         // Get the latest id (at this point, should be lib5).
2330         $lib5 = $generator->create_library_record($machinename, 'Test', 2, 1, 6);
2331         $latestlib = $this->framework->get_latest_library_version($machinename);
2332         $this->assertEquals($lib5->id, $latestlib->id);
2333     }