Merge branch 'MDL-63805-master' of git://github.com/jleyva/moodle into master
[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 defined('MOODLE_INTERNAL') || die();
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 setErrorMessage().
179      */
180     public function test_setErrorMessage() {
181         // Set an error message and an error code.
182         $message = "Error message";
183         $code = '404';
185         // Set an error message.
186         $this->framework->setErrorMessage($message, $code);
188         // Get the error messages.
189         $errormessages = $this->framework->getMessages('error');
191         $expected = new \stdClass();
192         $expected->code = 404;
193         $expected->message = 'Error message';
195         $this->assertEquals($expected, $errormessages[0]);
196     }
198     /**
199      * Test the behaviour of setInfoMessage().
200      */
201     public function test_setInfoMessage() {
202         $message = "Info message";
204         // Set an info message.
205         $this->framework->setInfoMessage($message);
207         // Get the info messages.
208         $infomessages = $this->framework->getMessages('info');
210         $expected = 'Info message';
212         $this->assertEquals($expected, $infomessages[0]);
213     }
215     /**
216      * Test the behaviour of getMessages() when requesting the info messages.
217      */
218     public function test_getMessages_info() {
219         // Set an info message.
220         $this->framework->setInfoMessage("Info message");
221         // Set an error message.
222         $this->framework->setErrorMessage("Error message 1", 404);
224         // Get the info messages.
225         $infomessages = $this->framework->getMessages('info');
227         $expected = 'Info message';
229         // Make sure that only the info message has been returned.
230         $this->assertCount(1, $infomessages);
231         $this->assertEquals($expected, $infomessages[0]);
233         $infomessages = $this->framework->getMessages('info');
235         // Make sure the info messages have now been removed.
236         $this->assertEmpty($infomessages);
237     }
239     /**
240      * Test the behaviour of getMessages() when requesting the error messages.
241      */
242     public function test_getMessages_error() {
243         // Set an info message.
244         $this->framework->setInfoMessage("Info message");
245         // Set an error message.
246         $this->framework->setErrorMessage("Error message 1", 404);
247         // Set another error message.
248         $this->framework->setErrorMessage("Error message 2", 403);
250         // Get the error messages.
251         $errormessages = $this->framework->getMessages('error');
253         // Make sure that only the error messages are being returned.
254         $this->assertEquals(2, count($errormessages));
256         $expected1 = (object) [
257             'code' => 404,
258             'message' => 'Error message 1'
259         ];
261         $expected2 = (object) [
262             'code' => 403,
263             'message' => 'Error message 2'
264         ];
266         $this->assertEquals($expected1, $errormessages[0]);
267         $this->assertEquals($expected2, $errormessages[1]);
269         $errormessages = $this->framework->getMessages('error');
271         // Make sure the info messages have now been removed.
272         $this->assertEmpty($errormessages);
273     }
275     /**
276      * Test the behaviour of t() when translating existing string that does not require any arguments.
277      */
278     public function test_t_existing_string_no_args() {
279         // Existing language string without passed arguments.
280         $translation = $this->framework->t('No copyright information available for this content.');
282         // Make sure the string translation has been returned.
283         $this->assertEquals('No copyright information available for this content.', $translation);
284     }
286     /**
287      * Test the behaviour of t() when translating existing string that does require parameters.
288      */
289     public function test_t_existing_string_args() {
290         // Existing language string with passed arguments.
291         $translation = $this->framework->t('Illegal option %option in %library',
292             ['%option' => 'example', '%library' => 'Test library']);
294         // Make sure the string translation has been returned.
295         $this->assertEquals('Illegal option example in Test library', $translation);
296     }
298     /**
299      * Test the behaviour of t() when translating non-existent string.
300      */
301     public function test_t_non_existent_string() {
302         // Non-existing language string.
303         $message = 'Random message %option';
305         $translation = $this->framework->t($message);
307         // Make sure a debugging message is triggered.
308         $this->assertDebuggingCalled("String translation cannot be found. Please add a string definition for '" .
309             $message . "' in the core_h5p component.");
310         // As the string does not exist in the mapping array, make sure the passed message is returned.
311         $this->assertEquals($message, $translation);
312     }
314     /**
315      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
316      * the folder name is parsable.
317      **/
318     public function test_getLibraryFileUrl() {
319         global $CFG;
321         $this->resetAfterTest();
323         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
324         // Create a library record.
325         $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
327         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/library.json";
329         // Get the URL of a file from an existing library. The provided folder name is parsable.
330         $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
332         // Make sure the expected URL is returned.
333         $this->assertEquals($expected, $actual);
334     }
336     /**
337      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a non-existent library and
338      * the folder name is parsable.
339      **/
340     public function test_getLibraryFileUrl_non_existent_library() {
341         $this->resetAfterTest();
343         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
344         // Create a library record.
345         $generator->create_library_record('Library', 'Lib', 1, 1);
347         // Get the URL of a file from a non-existent library. The provided folder name is parsable.
348         $actual = $this->framework->getLibraryFileUrl('Library2-1.1', 'library.json');
350         // Make sure a debugging message is triggered.
351         $this->assertDebuggingCalled('The library "Library2-1.1" does not exist.');
353         // Make sure that an URL is not returned.
354         $this->assertEquals(null, $actual);
355     }
357     /**
358      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from an existing library and
359      * the folder name is not parsable.
360      **/
361     public function test_getLibraryFileUrl_not_parsable_folder_name() {
362         $this->resetAfterTest();
364         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
365         // Create a library record.
366         $generator->create_library_record('Library', 'Lib', 1, 1);
368         // Get the URL of a file from an existing library. The provided folder name is not parsable.
369         $actual = $this->framework->getLibraryFileUrl('Library1.1', 'library.json');
371         // Make sure a debugging message is triggered.
372         $this->assertDebuggingCalled(
373             'The provided string value "Library1.1" is not a valid name for a library folder.');
375         // Make sure that an URL is not returned.
376         $this->assertEquals(null, $actual);
377     }
379     /**
380      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
381      * versions and the folder name is parsable.
382      **/
383     public function test_getLibraryFileUrl_library_has_multiple_versions() {
384         global $CFG;
386         $this->resetAfterTest();
388         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
389         // Create library records with a different minor version.
390         $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1);
391         $lib2 = $generator->create_library_record('Library', 'Lib', 1, 3);
393         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.3/library.json";
395         // Get the URL of a file from an existing library (Library 1.3). The provided folder name is parsable.
396         $actual = $this->framework->getLibraryFileUrl('Library-1.3', 'library.json');
398         // Make sure the proper URL (from the requested library version) is returned.
399         $this->assertEquals($expected, $actual);
400     }
402     /**
403      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a library that has multiple
404      * patch versions and the folder name is parsable.
405      **/
406     public function test_getLibraryFileUrl_library_has_multiple_patch_versions() {
407         global $CFG;
409         $this->resetAfterTest();
411         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
412         // Create library records with a different patch version.
413         $lib1 = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
414         $lib2 = $generator->create_library_record('Library', 'Lib', 1, 1, 4);
415         $lib3 = $generator->create_library_record('Library', 'Lib', 1, 1, 3);
417         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib2->id}/Library-1.1/library.json";
419         // Get the URL of a file from an existing library. The provided folder name is parsable.
420         $actual = $this->framework->getLibraryFileUrl('Library-1.1', 'library.json');
422         // Make sure the proper URL (from the latest library patch) is returned.
423         $this->assertEquals($expected, $actual);
424     }
426     /**
427      * Test the behaviour of getLibraryFileUrl() when requesting a file URL from a sub-folder
428      * of an existing library and the folder name is parsable.
429      **/
430     public function test_getLibraryFileUrl_library_subfolder() {
431         global $CFG;
433         $this->resetAfterTest();
435         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
436         // Create a library record.
437         $lib = $generator->create_library_record('Library', 'Lib', 1, 1);
439         $expected = "{$CFG->wwwroot}/pluginfile.php/1/core_h5p/libraries/{$lib->id}/Library-1.1/css/example.css";
441         // Get the URL of a file from a sub-folder from an existing library. The provided folder name is parsable.
442         $actual = $this->framework->getLibraryFileUrl('Library-1.1/css', 'example.css');
444         // Make sure the proper URL is returned.
445         $this->assertEquals($expected, $actual);
446     }
448     /**
449      * Test the behaviour of loadAddons().
450      */
451     public function test_loadAddons() {
452         $this->resetAfterTest();
454         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
456         // Create a Library addon (1.1).
457         $generator->create_library_record('Library', 'Lib', 1, 1, 2,
458             '', '/regex1/');
459         // Create a Library addon (1.3).
460         $generator->create_library_record('Library', 'Lib', 1, 3, 2,
461             '', '/regex2/');
462         // Create a Library addon (1.2).
463         $generator->create_library_record('Library', 'Lib', 1, 2, 2,
464             '', '/regex3/');
465         // Create a Library1 addon (1.2)
466         $generator->create_library_record('Library1', 'Lib1', 1, 2, 2,
467             '', '/regex11/');
469         // Load the latest version of each addon.
470         $addons = $this->framework->loadAddons();
472         // The addons array should return 2 results (Library and Library1 addon).
473         $this->assertCount(2, $addons);
475         // Make sure the version 1.3 is the latest 'Library' addon version.
476         $this->assertEquals('Library', $addons[0]['machineName']);
477         $this->assertEquals(1, $addons[0]['majorVersion']);
478         $this->assertEquals(3, $addons[0]['minorVersion']);
480         // Make sure the version 1.2 is the latest 'Library1' addon version.
481         $this->assertEquals('Library1', $addons[1]['machineName']);
482         $this->assertEquals(1, $addons[1]['majorVersion']);
483         $this->assertEquals(2, $addons[1]['minorVersion']);
484     }
486     /**
487      * Test the behaviour of loadLibraries().
488      */
489     public function test_loadLibraries() {
490         $this->resetAfterTest();
492         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
494         // Generate h5p related data.
495         $generator->generate_h5p_data();
497         // Load all libraries.
498         $libraries = $this->framework->loadLibraries();
500         // Make sure all libraries are returned.
501         $this->assertNotEmpty($libraries);
502         $this->assertCount(6, $libraries);
503         $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
504         $this->assertEquals('1', $libraries['MainLibrary'][0]->major_version);
505         $this->assertEquals('0', $libraries['MainLibrary'][0]->minor_version);
506         $this->assertEquals('1', $libraries['MainLibrary'][0]->patch_version);
507         $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
508     }
510     /**
511      * Test the behaviour of test_getLibraryId() when requesting an existing machine name.
512      */
513     public function test_getLibraryId_existing_machine_name() {
514         $this->resetAfterTest();
516         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
518         // Create a library.
519         $lib = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
521         // Request the library ID of the library with machine name 'Library'.
522         $libraryid = $this->framework->getLibraryId('Library');
524         // Make sure the library ID is being returned.
525         $this->assertNotFalse($libraryid);
526         $this->assertEquals($lib->id, $libraryid);
527     }
529     /**
530      * Test the behaviour of test_getLibraryId() when requesting a non-existent machine name.
531      */
532     public function test_getLibraryId_non_existent_machine_name() {
533         $this->resetAfterTest();
535         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
537         // Create a library.
538         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
540         // Request the library ID of the library with machinename => 'TestLibrary' (non-existent).
541         $libraryid = $this->framework->getLibraryId('TestLibrary');
543         // Make sure the library ID not being returned.
544         $this->assertFalse($libraryid);
545     }
547     /**
548      * Test the behaviour of test_getLibraryId() when requesting a non-existent major version.
549      */
550     public function test_getLibraryId_non_existent_major_version() {
551         $this->resetAfterTest();
553         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
555         // Create a library.
556         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
558         // Request the library ID of the library with machine name => 'Library', majorversion => 2 (non-existent).
559         $libraryid = $this->framework->getLibraryId('Library', 2);
561         // Make sure the library ID not being returned.
562         $this->assertFalse($libraryid);
563     }
565     /**
566      * Test the behaviour of test_getLibraryId() when requesting a non-existent minor version.
567      */
568     public function test_getLibraryId_non_existent_minor_version() {
569         $this->resetAfterTest();
571         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
573         // Create a library.
574         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
576         // Request the library ID of the library with machine name => 'Library',
577         // majorversion => 1,  minorversion => 2 (non-existent).
578         $libraryid = $this->framework->getLibraryId('Library', 1, 2);
580         // Make sure the library ID not being returned.
581         $this->assertFalse($libraryid);
582     }
584     /**
585      * Test the behaviour of isPatchedLibrary().
586      *
587      * @dataProvider test_isPatchedLibrary_provider
588      * @param array $libraryrecords Array containing data for the library creation
589      * @param array $testlibrary Array containing the test library data
590      * @param bool $expected The expectation whether the library is patched or not
591      **/
592     public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary, bool $expected): void {
593         $this->resetAfterTest();
595         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
597         foreach ($libraryrecords as $library) {
598             call_user_func_array([$generator, 'create_library_record'], $library);
599         }
601         $this->assertEquals($expected, $this->framework->isPatchedLibrary($testlibrary));
602     }
604     /**
605      * Data provider for test_isPatchedLibrary().
606      *
607      * @return array
608      */
609     public function test_isPatchedLibrary_provider(): array {
610         return [
611             'Unpatched library. No different versioning' => [
612                 [
613                     ['TestLibrary', 'Test', 1, 1, 2],
614                 ],
615                 [
616                     'machineName' => 'TestLibrary',
617                     'majorVersion' => 1,
618                     'minorVersion' => 1,
619                     'patchVersion' => 2
620                 ],
621                 false,
622             ],
623             'Major version identical; Minor version identical; Patch version newer' => [
624                 [
625                     ['TestLibrary', 'Test', 1, 1, 2],
626                 ],
627                 [
628                     'machineName' => 'TestLibrary',
629                     'majorVersion' => 1,
630                     'minorVersion' => 1,
631                     'patchVersion' => 3
632                 ],
633                 true,
634             ],
635             'Major version identical; Minor version newer; Patch version newer' => [
636                 [
637                     ['TestLibrary', 'Test', 1, 1, 2],
638                 ],
639                 [
640                     'machineName' => 'TestLibrary',
641                     'majorVersion' => 1,
642                     'minorVersion' => 2,
643                     'patchVersion' => 3
644                 ],
645                 false,
646             ],
647             'Major version identical; Minor version identical; Patch version older' => [
648                 [
649                     ['TestLibrary', 'Test', 1, 1, 2],
650                 ],
651                 [
652                     'machineName' => 'TestLibrary',
653                     'majorVersion' => 1,
654                     'minorVersion' => 1,
655                     'patchVersion' => 1
656                 ],
657                 false,
658             ],
659             'Major version identical; Minor version newer; Patch version older' => [
660                 [
661                     ['TestLibrary', 'Test', 1, 1, 2],
662                 ],
663                 [
664                     'machineName' => 'TestLibrary',
665                     'majorVersion' => 1,
666                     'minorVersion' => 2,
667                     'patchVersion' => 1
668                 ],
669                 false,
670             ],
671             'Major version newer; Minor version identical; Patch version older' => [
672                 [
673                     ['TestLibrary', 'Test', 1, 1, 2],
674                 ],
675                 [
676                     'machineName' => 'TestLibrary',
677                     'majorVersion' => 2,
678                     'minorVersion' => 1,
679                     'patchVersion' => 1
680                 ],
681                 false,
682             ],
683             'Major version newer; Minor version identical; Patch version newer' => [
684                 [
685                     ['TestLibrary', 'Test', 1, 1, 2],
686                 ],
687                 [
688                     'machineName' => 'TestLibrary',
689                     'majorVersion' => 2,
690                     'minorVersion' => 1,
691                     'patchVersion' => 3
692                 ],
693                 false,
694             ],
696             'Major version older; Minor version identical; Patch version older' => [
697                 [
698                     ['TestLibrary', 'Test', 1, 1, 2],
699                 ],
700                 [
701                     'machineName' => 'TestLibrary',
702                     'majorVersion' => 0,
703                     'minorVersion' => 1,
704                     'patchVersion' => 1
705                 ],
706                 false,
707             ],
708             'Major version older; Minor version identical; Patch version newer' => [
709                 [
710                     ['TestLibrary', 'Test', 1, 1, 2],
711                 ],
712                 [
713                     'machineName' => 'TestLibrary',
714                     'majorVersion' => 0,
715                     'minorVersion' => 1,
716                     'patchVersion' => 3
717                 ],
718                 false,
719             ],
720         ];
721     }
723     /**
724      * Test the behaviour of isInDevMode().
725      */
726     public function test_isInDevMode() {
727         $isdevmode = $this->framework->isInDevMode();
729         $this->assertFalse($isdevmode);
730     }
732     /**
733      * Test the behaviour of mayUpdateLibraries().
734      */
735     public function test_mayUpdateLibraries(): void {
736         global $DB;
738         $this->resetAfterTest();
740         // Create some users.
741         $contextsys = \context_system::instance();
742         $user = $this->getDataGenerator()->create_user();
743         $admin = get_admin();
744         $managerrole = $DB->get_record('role', ['shortname' => 'manager'], '*', MUST_EXIST);
745         $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
746         $manager = $this->getDataGenerator()->create_user();
747         role_assign($managerrole->id, $manager->id, $contextsys);
749         // Create a course with a label and enrol the user.
750         $course = $this->getDataGenerator()->create_course();
751         $label = $this->getDataGenerator()->create_module('label', ['course' => $course->id]);
752         list(, $labelcm) = get_course_and_cm_from_instance($label->id, 'label');
753         $contextlabel = \context_module::instance($labelcm->id);
754         $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
756         // Create the .h5p file.
757         $path = __DIR__ . '/fixtures/h5ptest.zip';
759         // Admin and manager should have permission to update libraries.
760         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextsys);
761         $this->framework->set_file($file);
762         $mayupdatelib = $this->framework->mayUpdateLibraries();
763         $this->assertTrue($mayupdatelib);
765         $file = helper::create_fake_stored_file_from_path($path, $manager->id, $contextsys);
766         $this->framework->set_file($file);
767         $mayupdatelib = $this->framework->mayUpdateLibraries();
768         $this->assertTrue($mayupdatelib);
770         // By default, normal user hasn't permission to update libraries (in both contexts, system and module label).
771         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
772         $this->framework->set_file($file);
773         $mayupdatelib = $this->framework->mayUpdateLibraries();
774         $this->assertFalse($mayupdatelib);
776         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
777         $this->framework->set_file($file);
778         $mayupdatelib = $this->framework->mayUpdateLibraries();
779         $this->assertFalse($mayupdatelib);
781         // If the current user (admin) can update libraries, the method should return true (even if the file userid hasn't the
782         // required capabilility in the file context).
783         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextlabel);
784         $this->framework->set_file($file);
785         $mayupdatelib = $this->framework->mayUpdateLibraries();
786         $this->assertTrue($mayupdatelib);
788         // If the update capability is assigned to the user, they should be able to update the libraries (only in the context
789         // where the capability has been assigned).
790         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
791         $this->framework->set_file($file);
792         $mayupdatelib = $this->framework->mayUpdateLibraries();
793         $this->assertFalse($mayupdatelib);
794         assign_capability('moodle/h5p:updatelibraries', CAP_ALLOW, $studentrole->id, $contextlabel);
795         $mayupdatelib = $this->framework->mayUpdateLibraries();
796         $this->assertTrue($mayupdatelib);
797         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
798         $this->framework->set_file($file);
799         $mayupdatelib = $this->framework->mayUpdateLibraries();
800         $this->assertFalse($mayupdatelib);
801     }
803     /**
804      * Test the behaviour of get_file() and set_file().
805      */
806     public function test_get_file(): void {
807         $this->resetAfterTest();
809         // Create some users.
810         $contextsys = \context_system::instance();
811         $user = $this->getDataGenerator()->create_user();
813         // The H5P file.
814         $path = __DIR__ . '/fixtures/h5ptest.zip';
816         // An error should be raised when it's called before initialitzing it.
817         $this->expectException('coding_exception');
818         $this->expectExceptionMessage('Using get_file() before file is set');
819         $this->framework->get_file();
821         // Check the value when only path and user are set.
822         $file = helper::create_fake_stored_file_from_path($path, $user->id);
823         $this->framework->set_file($file);
824         $file = $this->framework->get_file();
825         $this->assertEquals($user->id, $$file->get_userid());
826         $this->assertEquals($contextsys->id, $file->get_contextid());
828         // Check the value when also the context is set.
829         $course = $this->getDataGenerator()->create_course();
830         $contextcourse = \context_course::instance($course->id);
831         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextcourse);
832         $this->framework->set_file($file);
833         $file = $this->framework->get_file();
834         $this->assertEquals($user->id, $$file->get_userid());
835         $this->assertEquals($contextcourse->id, $file->get_contextid());
836     }
838     /**
839      * Test the behaviour of saveLibraryData() when saving data for a new library.
840      */
841     public function test_saveLibraryData_new_library() {
842         global $DB;
844         $this->resetAfterTest();
846         $librarydata = array(
847             'title' => 'Test',
848             'machineName' => 'TestLibrary',
849             'majorVersion' => '1',
850             'minorVersion' => '0',
851             'patchVersion' => '2',
852             'runnable' => 1,
853             'fullscreen' => 1,
854             'preloadedJs' => array(
855                 array(
856                     'path' => 'js/name.min.js'
857                 )
858             ),
859             'preloadedCss' => array(
860                 array(
861                     'path' => 'css/name.css'
862                 )
863             ),
864             'dropLibraryCss' => array(
865                 array(
866                     'machineName' => 'Name2'
867                 )
868             )
869         );
871         // Create a new library.
872         $this->framework->saveLibraryData($librarydata);
874         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
876         // Make sure the library data was properly saved.
877         $this->assertNotEmpty($library);
878         $this->assertNotEmpty($librarydata['libraryId']);
879         $this->assertEquals($librarydata['title'], $library->title);
880         $this->assertEquals($librarydata['machineName'], $library->machinename);
881         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
882         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
883         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
884         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
885         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
886         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
887     }
889     /**
890      * Test the behaviour of saveLibraryData() when saving (updating) data for an existing library.
891      */
892     public function test_saveLibraryData_existing_library() {
893         global $DB;
895         $this->resetAfterTest();
897         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
899         // Create a library record.
900         $library = $generator->create_library_record('TestLibrary', 'Test', 1, 0, 2);
902         $librarydata = array(
903             'libraryId' => $library->id,
904             'title' => 'Test1',
905             'machineName' => 'TestLibrary',
906             'majorVersion' => '1',
907             'minorVersion' => '2',
908             'patchVersion' => '2',
909             'runnable' => 1,
910             'fullscreen' => 1,
911             'preloadedJs' => array(
912                 array(
913                     'path' => 'js/name.min.js'
914                 )
915             ),
916             'preloadedCss' => array(
917                 array(
918                     'path' => 'css/name.css'
919                 )
920             ),
921             'dropLibraryCss' => array(
922                 array(
923                     'machineName' => 'Name2'
924                 )
925             )
926         );
928         // Update the library.
929         $this->framework->saveLibraryData($librarydata, false);
931         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
933         // Make sure the library data was properly updated.
934         $this->assertNotEmpty($library);
935         $this->assertNotEmpty($librarydata['libraryId']);
936         $this->assertEquals($librarydata['title'], $library->title);
937         $this->assertEquals($librarydata['machineName'], $library->machinename);
938         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
939         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
940         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
941         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
942         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
943         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
944     }
946     /**
947      * Test the behaviour of insertContent().
948      */
949     public function test_insertContent() {
950         global $DB;
952         $this->resetAfterTest();
954         $content = array(
955             'params' => json_encode(['param1' => 'Test']),
956             'library' => array(
957                 'libraryId' => 1
958             ),
959             'disable' => 8
960         );
962         // Insert h5p content.
963         $contentid = $this->framework->insertContent($content);
965         // Get the entered content from the db.
966         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
968         // Make sure the h5p content was properly inserted.
969         $this->assertNotEmpty($dbcontent);
970         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
971         $this->assertEquals($content['library']['libraryId'], $dbcontent->mainlibraryid);
972         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
973     }
975     /**
976      * Test the behaviour of insertContent().
977      */
978     public function test_insertContent_latestlibrary() {
979         global $DB;
981         $this->resetAfterTest();
983         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
984         // Create a library record.
985         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
987         $content = array(
988             'params' => json_encode(['param1' => 'Test']),
989             'library' => array(
990                 'libraryId' => 0,
991                 'machineName' => 'TestLibrary',
992             ),
993             'disable' => 8
994         );
996         // Insert h5p content.
997         $contentid = $this->framework->insertContent($content);
999         // Get the entered content from the db.
1000         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1002         // Make sure the h5p content was properly inserted.
1003         $this->assertNotEmpty($dbcontent);
1004         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1005         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1006         // As the libraryId was empty, the latest library has been used.
1007         $this->assertEquals($lib->id, $dbcontent->mainlibraryid);
1008     }
1010     /**
1011      * Test the behaviour of updateContent().
1012      */
1013     public function test_updateContent() {
1014         global $DB;
1016         $this->resetAfterTest();
1018         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1020         // Create a library record.
1021         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1023         // Create an h5p content with 'TestLibrary' as it's main library.
1024         $contentid = $generator->create_h5p_record($lib->id);
1026         $content = array(
1027             'id' => $contentid,
1028             'params' => json_encode(['param2' => 'Test2']),
1029             'library' => array(
1030                 'libraryId' => $lib->id
1031             ),
1032             'disable' => 8
1033         );
1035         // Update the h5p content.
1036         $this->framework->updateContent($content);
1038         $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]);
1040         // Make sure the h5p content was properly updated.
1041         $this->assertNotEmpty($h5pcontent);
1042         $this->assertEquals($content['params'], $h5pcontent->jsoncontent);
1043         $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid);
1044         $this->assertEquals($content['disable'], $h5pcontent->displayoptions);
1045     }
1047     /**
1048      * Test the behaviour of saveLibraryDependencies().
1049      */
1050     public function test_saveLibraryDependencies() {
1051         global $DB;
1053         $this->resetAfterTest();
1055         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1057         // Create a library 'Library'.
1058         $library = $generator->create_library_record('Library', 'Title');
1059         // Create a library 'DependencyLibrary1'.
1060         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1061         // Create a library 'DependencyLibrary2'.
1062         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1064         $dependencies = array(
1065             array(
1066                 'machineName' => $dependency1->machinename,
1067                 'majorVersion' => $dependency1->majorversion,
1068                 'minorVersion' => $dependency1->minorversion
1069             ),
1070             array(
1071                 'machineName' => $dependency2->machinename,
1072                 'majorVersion' => $dependency2->majorversion,
1073                 'minorVersion' => $dependency2->minorversion
1074             ),
1075         );
1077         // Set 'DependencyLibrary1' and 'DependencyLibrary2' as library dependencies of 'Library'.
1078         $this->framework->saveLibraryDependencies($library->id, $dependencies, 'preloaded');
1080         $libdependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library->id], 'id ASC');
1082         // Make sure the library dependencies for 'Library' are properly set.
1083         $this->assertEquals(2, count($libdependencies));
1084         $this->assertEquals($dependency1->id, reset($libdependencies)->requiredlibraryid);
1085         $this->assertEquals($dependency2->id, end($libdependencies)->requiredlibraryid);
1086     }
1088     /**
1089      * Test the behaviour of deleteContentData().
1090      */
1091     public function test_deleteContentData() {
1092         global $DB;
1094         $this->resetAfterTest();
1096         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1098         // Generate some h5p related data.
1099         $data = $generator->generate_h5p_data();
1100         $h5pid = $data->h5pcontent->h5pid;
1102         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1103         // Make sure the particular h5p content exists in the DB.
1104         $this->assertNotEmpty($h5pcontent);
1106         // Get the h5p content libraries from the DB.
1107         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1109         // Make sure the content libraries exists in the DB.
1110         $this->assertNotEmpty($h5pcontentlibraries);
1111         $this->assertCount(5, $h5pcontentlibraries);
1113         // Delete the h5p content and it's related data.
1114         $this->framework->deleteContentData($h5pid);
1116         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1117         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1119         // The particular h5p content should no longer exist in the db.
1120         $this->assertEmpty($h5pcontent);
1121         // The particular content libraries should no longer exist in the db.
1122         $this->assertEmpty($h5pcontentlibraries);
1123     }
1125     /**
1126      * Test the behaviour of deleteLibraryUsage().
1127      */
1128     public function test_deleteLibraryUsage() {
1129         global $DB;
1131         $this->resetAfterTest();
1133         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1135         // Generate some h5p related data.
1136         $data = $generator->generate_h5p_data();
1137         $h5pid = $data->h5pcontent->h5pid;
1139         // Get the h5p content libraries from the DB.
1140         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1142         // The particular h5p content should have 5 content libraries.
1143         $this->assertNotEmpty($h5pcontentlibraries);
1144         $this->assertCount(5, $h5pcontentlibraries);
1146         // Delete the h5p content and it's related data.
1147         $this->framework->deleteLibraryUsage($h5pid);
1149         // Get the h5p content libraries from the DB.
1150         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1152         // The particular h5p content libraries should no longer exist in the db.
1153         $this->assertEmpty($h5pcontentlibraries);
1154     }
1156     /**
1157      * Test the behaviour of test_saveLibraryUsage().
1158      */
1159     public function test_saveLibraryUsage() {
1160         global $DB;
1162         $this->resetAfterTest();
1164         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1166         // Create a library 'Library'.
1167         $library = $generator->create_library_record('Library', 'Title');
1168         // Create a library 'DependencyLibrary1'.
1169         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1170         // Create a library 'DependencyLibrary2'.
1171         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1172         // Create an h5p content with 'Library' as it's main library.
1173         $contentid = $generator->create_h5p_record($library->id);
1175         $dependencies = array(
1176             array(
1177                 'library' => array(
1178                     'libraryId' => $dependency1->id,
1179                     'machineName' => $dependency1->machinename,
1180                     'dropLibraryCss' => $dependency1->droplibrarycss
1181                 ),
1182                 'type' => 'preloaded',
1183                 'weight' => 1
1184             ),
1185             array(
1186                 'library' => array(
1187                     'libraryId' => $dependency2->id,
1188                     'machineName' => $dependency2->machinename,
1189                     'dropLibraryCss' => $dependency2->droplibrarycss
1190                 ),
1191                 'type' => 'preloaded',
1192                 'weight' => 2
1193             ),
1194         );
1196         // Save 'DependencyLibrary1' and 'DependencyLibrary2' as h5p content libraries.
1197         $this->framework->saveLibraryUsage($contentid, $dependencies);
1199         // Get the h5p content libraries from the DB.
1200         $libdependencies = $DB->get_records('h5p_contents_libraries', ['h5pid' => $contentid], 'id ASC');
1202         // Make sure that 'DependencyLibrary1' and 'DependencyLibrary2' are properly set as h5p content libraries.
1203         $this->assertEquals(2, count($libdependencies));
1204         $this->assertEquals($dependency1->id, reset($libdependencies)->libraryid);
1205         $this->assertEquals($dependency2->id, end($libdependencies)->libraryid);
1206     }
1208     /**
1209      * Test the behaviour of getLibraryUsage() without skipping a particular h5p content.
1210      */
1211     public function test_getLibraryUsage_no_skip_content() {
1212         $this->resetAfterTest();
1214         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1216         // Generate h5p related data.
1217         $generateddata = $generator->generate_h5p_data();
1218         // The Id of the library 'Library1'.
1219         $library1id = $generateddata->lib1->data->id;
1220         // The Id of the library 'Library2'.
1221         $library2id = $generateddata->lib2->data->id;
1222         // The Id of the library 'Library5'.
1223         $library5id = $generateddata->lib5->data->id;
1225         // Get the library usage for 'Library1' (do not skip content).
1226         $data = $this->framework->getLibraryUsage($library1id);
1228         $expected = array(
1229             'content' => 1,
1230             'libraries' => 1
1231         );
1233         // Make sure 'Library1' is used by 1 content and is a dependency to 1 library.
1234         $this->assertEquals($expected, $data);
1236         // Get the library usage for 'Library2' (do not skip content).
1237         $data = $this->framework->getLibraryUsage($library2id);
1239         $expected = array(
1240             'content' => 1,
1241             'libraries' => 2,
1242         );
1244         // Make sure 'Library2' is used by 1 content and is a dependency to 2 libraries.
1245         $this->assertEquals($expected, $data);
1247          // Get the library usage for 'Library5' (do not skip content).
1248         $data = $this->framework->getLibraryUsage($library5id);
1250         $expected = array(
1251             'content' => 0,
1252             'libraries' => 1,
1253         );
1255         // Make sure 'Library5' is not used by any content and is a dependency to 1 library.
1256         $this->assertEquals($expected, $data);
1257     }
1259     /**
1260      * Test the behaviour of getLibraryUsage() when skipping a particular content.
1261      */
1262     public function test_getLibraryUsage_skip_content() {
1263         $this->resetAfterTest();
1265         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1267         // Generate h5p related data.
1268         $generateddata = $generator->generate_h5p_data();
1269         // The Id of the library 'Library1'.
1270         $library1id = $generateddata->lib1->data->id;
1272         // Get the library usage for 'Library1' (skip content).
1273         $data = $this->framework->getLibraryUsage($library1id, true);
1274         $expected = array(
1275             'content' => -1,
1276             'libraries' => 1,
1277         );
1279         // Make sure 'Library1' is a dependency to 1 library.
1280         $this->assertEquals($expected, $data);
1281     }
1283     /**
1284      * Test the behaviour of loadLibrary() when requesting an existing library.
1285      */
1286     public function test_loadLibrary_existing_library() {
1287         $this->resetAfterTest();
1289         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1291         // Generate h5p related data.
1292         $generateddata = $generator->generate_h5p_data();
1293         // The library data of 'Library1'.
1294         $library1 = $generateddata->lib1->data;
1295         // The library data of 'Library5'.
1296         $library5 = $generateddata->lib5->data;
1298         // The preloaded dependencies.
1299         $preloadeddependencies = array();
1301         foreach ($generateddata->lib1->dependencies as $preloadeddependency) {
1302             $preloadeddependencies[] = array(
1303                 'machineName' => $preloadeddependency->machinename,
1304                 'majorVersion' => $preloadeddependency->majorversion,
1305                 'minorVersion' => $preloadeddependency->minorversion
1306             );
1307         }
1309         // Create a dynamic dependency.
1310         $generator->create_library_dependency_record($library1->id, $library5->id, 'dynamic');
1312         $dynamicdependencies[] = array(
1313             'machineName' => $library5->machinename,
1314             'majorVersion' => $library5->majorversion,
1315             'minorVersion' => $library5->minorversion
1316         );
1318         // Load 'Library1' data.
1319         $data = $this->framework->loadLibrary($library1->machinename, $library1->majorversion,
1320             $library1->minorversion);
1322         $expected = array(
1323             'libraryId' => $library1->id,
1324             'title' => $library1->title,
1325             'machineName' => $library1->machinename,
1326             'majorVersion' => $library1->majorversion,
1327             'minorVersion' => $library1->minorversion,
1328             'patchVersion' => $library1->patchversion,
1329             'runnable' => $library1->runnable,
1330             'fullscreen' => $library1->fullscreen,
1331             'embedTypes' => $library1->embedtypes,
1332             'preloadedJs' => $library1->preloadedjs,
1333             'preloadedCss' => $library1->preloadedcss,
1334             'dropLibraryCss' => $library1->droplibrarycss,
1335             'semantics' => $library1->semantics,
1336             'preloadedDependencies' => $preloadeddependencies,
1337             'dynamicDependencies' => $dynamicdependencies
1338         );
1340         // Make sure the 'Library1' data is properly loaded.
1341         $this->assertEquals($expected, $data);
1342     }
1344     /**
1345      * Test the behaviour of loadLibrary() when requesting a non-existent library.
1346      */
1347     public function test_loadLibrary_non_existent_library() {
1348         $this->resetAfterTest();
1350         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1352         // Generate h5p related data.
1353         $generator->generate_h5p_data();
1355         // Attempt to load a non-existent library.
1356         $data = $this->framework->loadLibrary('MissingLibrary', 1, 2);
1358         // Make sure nothing is loaded.
1359         $this->assertFalse($data);
1360     }
1362     /**
1363      * Test the behaviour of loadLibrarySemantics().
1364      *
1365      * @dataProvider test_loadLibrarySemantics_provider
1366      * @param array $libraryrecords Array containing data for the library creation
1367      * @param array $testlibrary Array containing the test library data
1368      * @param string $expected The expected semantics value
1369      **/
1370     public function test_loadLibrarySemantics(array $libraryrecords, array $testlibrary, string $expected): void {
1371         $this->resetAfterTest();
1373         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1375         foreach ($libraryrecords as $library) {
1376             call_user_func_array([$generator, 'create_library_record'], $library);
1377         }
1379         $this->assertEquals($expected, $this->framework->loadLibrarySemantics(
1380             $testlibrary['machinename'], $testlibrary['majorversion'], $testlibrary['minorversion']));
1381     }
1383     /**
1384      * Data provider for test_loadLibrarySemantics().
1385      *
1386      * @return array
1387      */
1388     public function test_loadLibrarySemantics_provider(): array {
1390         $semantics = json_encode(
1391             [
1392                 'type' => 'text',
1393                 'name' => 'text',
1394                 'label' => 'Plain text',
1395                 'description' => 'Please add some text'
1396             ]
1397         );
1399         return [
1400             'Library with semantics' => [
1401                 [
1402                     ['Library1', 'Lib1', 1, 1, 2, $semantics],
1403                 ],
1404                 [
1405                     'machinename' => 'Library1',
1406                     'majorversion' => 1,
1407                     'minorversion' => 1
1408                 ],
1409                 $semantics,
1410             ],
1411             'Library without semantics' => [
1412                 [
1413                     ['Library2', 'Lib2', 1, 2, 2, ''],
1414                 ],
1415                 [
1416                     'machinename' => 'Library2',
1417                     'majorversion' => 1,
1418                     'minorversion' => 2
1419                 ],
1420                 '',
1421             ]
1422         ];
1423     }
1425     /**
1426      * Test the behaviour of alterLibrarySemantics().
1427      */
1428     public function test_alterLibrarySemantics() {
1429         global $DB;
1431         $this->resetAfterTest();
1433         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1435         $semantics = json_encode(
1436             array(
1437                 'type' => 'text',
1438                 'name' => 'text',
1439                 'label' => 'Plain text',
1440                 'description' => 'Please add some text'
1441             )
1442         );
1444         // Create a library 'Library1' with semantics.
1445         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2, $semantics);
1447         $updatedsemantics = array(
1448             'type' => 'text',
1449             'name' => 'updated text',
1450             'label' => 'Updated text',
1451             'description' => 'Please add some text'
1452         );
1454         // Alter the semantics of 'Library1'.
1455         $this->framework->alterLibrarySemantics($updatedsemantics, 'Library1', 1, 1);
1457         // Get the semantics of 'Library1' from the DB.
1458         $currentsemantics = $DB->get_field('h5p_libraries', 'semantics', array('id' => $library1->id));
1460         // The semantics for Library1 shouldn't be updated.
1461         $this->assertEquals($semantics, $currentsemantics);
1462     }
1464     /**
1465      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1466      * dependencies of an existing library.
1467      */
1468     public function test_deleteLibraryDependencies_existing_library() {
1469         global $DB;
1471         $this->resetAfterTest();
1473         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1475         // Generate h5p related data.
1476         $data = $generator->generate_h5p_data();
1477         // The data of the library 'Library1'.
1478         $library1 = $data->lib1->data;
1480         // Get the dependencies of 'Library1'.
1481         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1482         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1483         $this->assertCount(3, $dependencies);
1485         // Delete the dependencies of 'Library1'.
1486         $this->framework->deleteLibraryDependencies($library1->id);
1488         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1489         // The 'Library1' should have 0 dependencies.
1490         $this->assertCount(0, $dependencies);
1491     }
1493     /**
1494      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1495      * dependencies of a non-existent library.
1496      */
1497     public function test_deleteLibraryDependencies_non_existent_library() {
1498         global $DB;
1500         $this->resetAfterTest();
1502         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1504         // Generate h5p related data.
1505         $data = $generator->generate_h5p_data();
1506         // The data of the library 'Library1'.
1507         $library1 = $data->lib1->data;
1509         // Get the dependencies of 'Library1'.
1510         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1511         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1512         $this->assertCount(3, $dependencies);
1514         // Delete the dependencies of a non-existent library.
1515         $this->framework->deleteLibraryDependencies(0);
1517         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1518         // The 'Library1' should have 3 dependencies.
1519         $this->assertCount(3, $dependencies);
1520     }
1522     /**
1523      * Test the behaviour of deleteLibrary().
1524      */
1525     public function test_deleteLibrary() {
1526         global $DB;
1528         $this->resetAfterTest();
1530         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1532         // Generate h5p related data.
1533         $data = $generator->generate_h5p_data(true);
1534         // The data of the 'Library1' library.
1535         $library1 = $data->lib1->data;
1537         // Get the library dependencies of 'Library1'.
1538         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1540         // The 'Library1' should have 3 library dependencies ('Library2', 'Library3', 'Library4').
1541         $this->assertCount(3, $dependencies);
1543         // Return the created 'Library1' files.
1544         $libraryfiles = $DB->get_records('files',
1545             array(
1546                 'component' => \core_h5p\file_storage::COMPONENT,
1547                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1548                 'itemid' => $library1->id
1549             )
1550         );
1552         // The library ('Library1') should have 7 related folders/files.
1553         $this->assertCount(7, $libraryfiles);
1555         // Delete the library.
1556         $this->framework->deleteLibrary($library1);
1558         $lib1 = $DB->get_record('h5p_libraries', ['machinename' => $library1->machinename]);
1559         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1560         $libraryfiles = $DB->get_records('files',
1561             array(
1562                 'component' => \core_h5p\file_storage::COMPONENT,
1563                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1564                 'itemid' => $library1->id
1565             )
1566         );
1568         // The 'Library1' should not exist.
1569         $this->assertEmpty($lib1);
1570         // The library ('Library1')  should have 0 dependencies.
1571         $this->assertCount(0, $dependencies);
1572         // The library (library1) should have 0 related folders/files.
1573         $this->assertCount(0, $libraryfiles);
1574     }
1576     /**
1577      * Test the behaviour of loadContent().
1578      */
1579     public function test_loadContent() {
1580         global $DB;
1582         $this->resetAfterTest();
1584         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1586         // Generate h5p related data.
1587         $data = $generator->generate_h5p_data();
1588         // The Id of the created h5p content.
1589         $h5pid = $data->h5pcontent->h5pid;
1590         // Get the h5p content data from the DB.
1591         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1592         // The data of content's main library ('MainLibrary').
1593         $mainlibrary = $data->mainlib->data;
1595         // Load the h5p content.
1596         $content = $this->framework->loadContent($h5pid);
1598         $expected = array(
1599             'id' => $h5p->id,
1600             'params' => $h5p->jsoncontent,
1601             'embedType' => 'iframe',
1602             'disable' => $h5p->displayoptions,
1603             'title' => $mainlibrary->title,
1604             'slug' => \H5PCore::slugify($mainlibrary->title) . '-' . $h5p->id,
1605             'filtered' => $h5p->filtered,
1606             'libraryId' => $mainlibrary->id,
1607             'libraryName' => $mainlibrary->machinename,
1608             'libraryMajorVersion' => $mainlibrary->majorversion,
1609             'libraryMinorVersion' => $mainlibrary->minorversion,
1610             'libraryEmbedTypes' => $mainlibrary->embedtypes,
1611             'libraryFullscreen' => $mainlibrary->fullscreen,
1612             'metadata' => '',
1613             'pathnamehash' => $h5p->pathnamehash
1614         );
1616         $params = json_decode($h5p->jsoncontent);
1617         if (empty($params->metadata)) {
1618             $params->metadata = new \stdClass();
1619         }
1620         $expected['metadata'] = $params->metadata;
1621         $expected['params'] = json_encode($params->params ?? $params);
1623         // The returned content should match the expected array.
1624         $this->assertEquals($expected, $content);
1625     }
1627     /**
1628      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1629      * without specifying the dependency type.
1630      */
1631     public function test_loadContentDependencies_no_type_defined() {
1632         $this->resetAfterTest();
1634         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1636         // Generate h5p related data.
1637         $data = $generator->generate_h5p_data();
1638         // The Id of the h5p content.
1639         $h5pid = $data->h5pcontent->h5pid;
1640         // The content dependencies.
1641         $dependencies = $data->h5pcontent->contentdependencies;
1643         // Add Library5 as a content dependency (dynamic dependency type).
1644         $library5 = $data->lib5->data;
1645         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1647         // Get all content dependencies.
1648         $contentdependencies = $this->framework->loadContentDependencies($h5pid);
1650         $expected = array();
1651         foreach ($dependencies as $dependency) {
1652             $expected[$dependency->machinename] = array(
1653                 'libraryId' => $dependency->id,
1654                 'machineName' => $dependency->machinename,
1655                 'majorVersion' => $dependency->majorversion,
1656                 'minorVersion' => $dependency->minorversion,
1657                 'patchVersion' => $dependency->patchversion,
1658                 'preloadedCss' => $dependency->preloadedcss,
1659                 'preloadedJs' => $dependency->preloadedjs,
1660                 'dropCss' => '0',
1661                 'dependencyType' => 'preloaded'
1662             );
1663         }
1665         $expected = array_merge($expected,
1666             array(
1667                 'Library5' => array(
1668                     'libraryId' => $library5->id,
1669                     'machineName' => $library5->machinename,
1670                     'majorVersion' => $library5->majorversion,
1671                     'minorVersion' => $library5->minorversion,
1672                     'patchVersion' => $library5->patchversion,
1673                     'preloadedCss' => $library5->preloadedcss,
1674                     'preloadedJs' => $library5->preloadedjs,
1675                     'dropCss' => '0',
1676                     'dependencyType' => 'dynamic'
1677                 )
1678             )
1679         );
1681         // The loaded content dependencies should return 6 libraries.
1682         $this->assertCount(6, $contentdependencies);
1683         $this->assertEquals($expected, $contentdependencies);
1684     }
1686     /**
1687      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1688      * with specifying the dependency type.
1689      */
1690     public function test_loadContentDependencies_type_defined() {
1691         $this->resetAfterTest();
1693         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1695         // Generate h5p related data.
1696         $data = $generator->generate_h5p_data();
1697         // The Id of the h5p content.
1698         $h5pid = $data->h5pcontent->h5pid;
1699         // The content dependencies.
1700         $dependencies = $data->h5pcontent->contentdependencies;
1702         // Add Library5 as a content dependency (dynamic dependency type).
1703         $library5 = $data->lib5->data;
1704         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1706         // Load all content dependencies of dependency type 'preloaded'.
1707         $preloadeddependencies = $this->framework->loadContentDependencies($h5pid, 'preloaded');
1709         $expected = array();
1710         foreach ($dependencies as $dependency) {
1711             $expected[$dependency->machinename] = array(
1712                 'libraryId' => $dependency->id,
1713                 'machineName' => $dependency->machinename,
1714                 'majorVersion' => $dependency->majorversion,
1715                 'minorVersion' => $dependency->minorversion,
1716                 'patchVersion' => $dependency->patchversion,
1717                 'preloadedCss' => $dependency->preloadedcss,
1718                 'preloadedJs' => $dependency->preloadedjs,
1719                 'dropCss' => '0',
1720                 'dependencyType' => 'preloaded'
1721             );
1722         }
1724         // The loaded content dependencies should return 5 libraries.
1725         $this->assertCount(5, $preloadeddependencies);
1726         $this->assertEquals($expected, $preloadeddependencies);
1728         // Load all content dependencies of dependency type 'dynamic'.
1729         $dynamicdependencies = $this->framework->loadContentDependencies($h5pid, 'dynamic');
1731         $expected = array(
1732             'Library5' => array(
1733                 'libraryId' => $library5->id,
1734                 'machineName' => $library5->machinename,
1735                 'majorVersion' => $library5->majorversion,
1736                 'minorVersion' => $library5->minorversion,
1737                 'patchVersion' => $library5->patchversion,
1738                 'preloadedCss' => $library5->preloadedcss,
1739                 'preloadedJs' => $library5->preloadedjs,
1740                 'dropCss' => '0',
1741                 'dependencyType' => 'dynamic'
1742             )
1743         );
1745         // The loaded content dependencies should now return 1 library.
1746         $this->assertCount(1, $dynamicdependencies);
1747         $this->assertEquals($expected, $dynamicdependencies);
1748     }
1750     /**
1751      * Test the behaviour of getOption().
1752      */
1753     public function test_getOption(): void {
1754         $this->resetAfterTest();
1756         // Get value for display_option_download.
1757         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_DOWNLOAD);
1758         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1759         $this->assertEquals($expected, $value);
1761         // Get value for display_option_embed using default value (it should be ignored).
1762         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_EMBED, \H5PDisplayOptionBehaviour::NEVER_SHOW);
1763         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1764         $this->assertEquals($expected, $value);
1766         // Get value for unexisting setting without default.
1767         $value = $this->framework->getOption('unexistingsetting');
1768         $expected = false;
1769         $this->assertEquals($expected, $value);
1771         // Get value for unexisting setting with default.
1772         $value = $this->framework->getOption('unexistingsetting', 'defaultvalue');
1773         $expected = 'defaultvalue';
1774         $this->assertEquals($expected, $value);
1775     }
1777     /**
1778      * Test the behaviour of setOption().
1779      */
1780     public function test_setOption(): void {
1781         $this->resetAfterTest();
1783         // Set value for 'newsetting' setting.
1784         $name = 'newsetting';
1785         $value = $this->framework->getOption($name);
1786         $this->assertEquals(false, $value);
1787         $newvalue = 'value1';
1788         $this->framework->setOption($name, $newvalue);
1789         $value = $this->framework->getOption($name);
1790         $this->assertEquals($newvalue, $value);
1792         // Set value for display_option_download and then get it again. Check it hasn't changed.
1793         $name = \H5PCore::DISPLAY_OPTION_DOWNLOAD;
1794         $newvalue = \H5PDisplayOptionBehaviour::NEVER_SHOW;
1795         $this->framework->setOption($name, $newvalue);
1796         $value = $this->framework->getOption($name);
1797         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1798         $this->assertEquals($expected, $value);
1799     }
1801     /**
1802      * Test the behaviour of updateContentFields().
1803      */
1804     public function test_updateContentFields() {
1805         global $DB;
1807         $this->resetAfterTest();
1809         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1811         // Create 'Library1' library.
1812         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1813         // Create 'Library2' library.
1814         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1816         // Create an h5p content with 'Library1' as it's main library.
1817         $h5pid = $generator->create_h5p_record($library1->id, 'iframe');
1819         $updatedata = array(
1820             'jsoncontent' => json_encode(['value' => 'test']),
1821             'mainlibraryid' => $library2->id
1822         );
1824         // Update h5p content fields.
1825         $this->framework->updateContentFields($h5pid, $updatedata);
1827         // Get the h5p content from the DB.
1828         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1830         $expected = json_encode(['value' => 'test']);
1832         // Make sure the h5p content fields are properly updated.
1833         $this->assertEquals($expected, $h5p->jsoncontent);
1834         $this->assertEquals($library2->id, $h5p->mainlibraryid);
1835     }
1837     /**
1838      * Test the behaviour of clearFilteredParameters().
1839      */
1840     public function test_clearFilteredParameters() {
1841         global $DB;
1843         $this->resetAfterTest();
1845         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1847         // Create 3 libraries.
1848         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1849         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1850         $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1852         // Create h5p content with 'Library1' as a main library.
1853         $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1854         // Create h5p content with 'Library1' as a main library.
1855         $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1856         // Create h5p content with 'Library2' as a main library.
1857         $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1858         // Create h5p content with 'Library3' as a main library.
1859         $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1861         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1862         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1863         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1864         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1866         // The filtered parameters should be present in each h5p content.
1867         $this->assertNotEmpty($h5pcontent1->filtered);
1868         $this->assertNotEmpty($h5pcontent2->filtered);
1869         $this->assertNotEmpty($h5pcontent3->filtered);
1870         $this->assertNotEmpty($h5pcontent4->filtered);
1872         // Clear the filtered parameters for contents that have library1 and library3 as
1873         // their main library.
1874         $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1876         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1877         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1878         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1879         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1881         // The filtered parameters should be still present only for the content that has
1882         // library 2 as a main library.
1883         $this->assertEmpty($h5pcontent1->filtered);
1884         $this->assertEmpty($h5pcontent2->filtered);
1885         $this->assertNotEmpty($h5pcontent3->filtered);
1886         $this->assertEmpty($h5pcontent4->filtered);
1887     }
1889     /**
1890      * Test the behaviour of getNumNotFiltered().
1891      */
1892     public function test_getNumNotFiltered() {
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         $countnotfiltered = $this->framework->getNumNotFiltered();
1930         // 3 contents don't have their parameters filtered.
1931         $this->assertEquals(3, $countnotfiltered);
1932     }
1934     /**
1935      * Test the behaviour of getNumContent().
1936      */
1937     public function test_getNumContent() {
1938         $this->resetAfterTest();
1940         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1942         // Generate h5p related data.
1943         $data = $generator->generate_h5p_data();
1945         // The 'MainLibrary' library data.
1946         $mainlibrary = $data->mainlib->data;
1948         // The 'Library1' library data.
1949         $library1 = $data->lib1->data;
1951         // Create new h5p content with MainLibrary as a main library.
1952         $generator->create_h5p_record($mainlibrary->id);
1954         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
1955         $countmainlib = $this->framework->getNumContent($mainlibrary->id);
1957         // Get the number of h5p contents that are using 'Library1' as their main library.
1958         $countlib1 = $this->framework->getNumContent($library1->id);
1960         // Make sure that 2 contents are using MainLibrary as their main library.
1961         $this->assertEquals(2, $countmainlib);
1962         // Make sure that 0 contents are using Library1 as their main library.
1963         $this->assertEquals(0, $countlib1);
1964     }
1966     /**
1967      * Test the behaviour of getNumContent() when certain contents are being skipped.
1968      */
1969     public function test_getNumContent_skip_content() {
1970         $this->resetAfterTest();
1972         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1974         // Generate h5p related data.
1975         $data = $generator->generate_h5p_data();
1977         // The 'MainLibrary' library data.
1978         $mainlibrary = $data->mainlib->data;
1980         // Create new h5p content with MainLibrary as a main library.
1981         $h5pcontentid = $generator->create_h5p_record($mainlibrary->id);
1983         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
1984         // Skip the newly created content $h5pcontentid.
1985         $countmainlib = $this->framework->getNumContent($mainlibrary->id, [$h5pcontentid]);
1987         // Make sure that 1 content is returned instead of 2 ($h5pcontentid being skipped).
1988         $this->assertEquals(1, $countmainlib);
1989     }
1991     /**
1992      * Test the behaviour of isContentSlugAvailable().
1993      */
1994     public function test_isContentSlugAvailable() {
1995         $this->resetAfterTest();
1997         $slug = 'h5p-test-slug-1';
1999         // Currently this returns always true. The slug is generated as a unique value for
2000         // each h5p content and it is not stored in the h5p content table.
2001         $isslugavailable = $this->framework->isContentSlugAvailable($slug);
2003         $this->assertTrue($isslugavailable);
2004     }
2006     /**
2007      * Test that a record is stored for cached assets.
2008      */
2009     public function test_saveCachedAssets() {
2010         global $DB;
2012         $this->resetAfterTest();
2014         $libraries = array(
2015             array(
2016                 'machineName' => 'H5P.TestLib',
2017                 'libraryId' => 405,
2018             ),
2019             array(
2020                 'FontAwesome' => 'FontAwesome',
2021                 'libraryId' => 406,
2022             ),
2023             array(
2024                 'machineName' => 'H5P.SecondLib',
2025                 'libraryId' => 407,
2026             ),
2027         );
2029         $key = 'testhashkey';
2031         $this->framework->saveCachedAssets($key, $libraries);
2033         $records = $DB->get_records('h5p_libraries_cachedassets');
2035         $this->assertCount(3, $records);
2036     }
2038     /**
2039      * Test that the correct libraries are removed from the cached assets table
2040      */
2041     public function test_deleteCachedAssets() {
2042         global $DB;
2044         $this->resetAfterTest();
2046         $libraries = array(
2047             array(
2048                 'machineName' => 'H5P.TestLib',
2049                 'libraryId' => 405,
2050             ),
2051             array(
2052                 'FontAwesome' => 'FontAwesome',
2053                 'libraryId' => 406,
2054             ),
2055             array(
2056                 'machineName' => 'H5P.SecondLib',
2057                 'libraryId' => 407,
2058             ),
2059         );
2061         $key1 = 'testhashkey';
2062         $this->framework->saveCachedAssets($key1, $libraries);
2064         $libraries = array(
2065             array(
2066                 'machineName' => 'H5P.DiffLib',
2067                 'libraryId' => 408,
2068             ),
2069             array(
2070                 'FontAwesome' => 'FontAwesome',
2071                 'libraryId' => 406,
2072             ),
2073             array(
2074                 'machineName' => 'H5P.ThirdLib',
2075                 'libraryId' => 409,
2076             ),
2077         );
2079         $key2 = 'secondhashkey';
2080         $this->framework->saveCachedAssets($key2, $libraries);
2082         $libraries = array(
2083             array(
2084                 'machineName' => 'H5P.AnotherDiffLib',
2085                 'libraryId' => 410,
2086             ),
2087             array(
2088                 'FontAwesome' => 'NotRelated',
2089                 'libraryId' => 411,
2090             ),
2091             array(
2092                 'machineName' => 'H5P.ForthLib',
2093                 'libraryId' => 412,
2094             ),
2095         );
2097         $key3 = 'threeforthewin';
2098         $this->framework->saveCachedAssets($key3, $libraries);
2100         $records = $DB->get_records('h5p_libraries_cachedassets');
2101         $this->assertCount(9, $records);
2103         // Selecting one library id will result in all related library entries also being deleted.
2104         // Going to use the FontAwesome library id. The first two hashes should be returned.
2105         $hashes = $this->framework->deleteCachedAssets(406);
2106         $this->assertCount(2, $hashes);
2107         $index = array_search($key1, $hashes);
2108         $this->assertEquals($key1, $hashes[$index]);
2109         $index = array_search($key2, $hashes);
2110         $this->assertEquals($key2, $hashes[$index]);
2111         $index = array_search($key3, $hashes);
2112         $this->assertFalse($index);
2114         // Check that the records have been removed as well.
2115         $records = $DB->get_records('h5p_libraries_cachedassets');
2116         $this->assertCount(3, $records);
2117     }
2119     /**
2120      * Test the behaviour of getLibraryContentCount().
2121      */
2122     public function test_getLibraryContentCount() {
2123         $this->resetAfterTest();
2125         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2127         // Generate h5p related data.
2128         $data = $generator->generate_h5p_data();
2130         // The 'MainLibrary' library data.
2131         $mainlibrary = $data->mainlib->data;
2133         // The 'Library2' library data.
2134         $library2 = $data->lib2->data;
2136         // Create new h5p content with Library2 as it's main library.
2137         $generator->create_h5p_record($library2->id);
2139         // Create new h5p content with MainLibrary as it's main library.
2140         $generator->create_h5p_record($mainlibrary->id);
2142         $countlibrarycontent = $this->framework->getLibraryContentCount();
2144         $expected = array(
2145             "{$mainlibrary->machinename} {$mainlibrary->majorversion}.{$mainlibrary->minorversion}" => 2,
2146             "{$library2->machinename} {$library2->majorversion}.{$library2->minorversion}" => 1,
2147         );
2149         // MainLibrary and Library1 are currently main libraries to the existing h5p contents.
2150         // Should return the number of cases where MainLibrary and Library1 are main libraries to an h5p content.
2151         $this->assertEquals($expected, $countlibrarycontent);
2152     }
2154     /**
2155      * Test the behaviour of test_libraryHasUpgrade().
2156      *
2157      * @dataProvider test_libraryHasUpgrade_provider
2158      * @param array $libraryrecords Array containing data for the library creation
2159      * @param array $testlibrary Array containing the test library data
2160      * @param bool $expected The expectation whether the library is patched or not
2161      **/
2162     public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary, bool $expected): void {
2163         $this->resetAfterTest();
2165         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2167         foreach ($libraryrecords as $library) {
2168             call_user_func_array([$generator, 'create_library_record'], $library);
2169         }
2171         $this->assertEquals($expected, $this->framework->libraryHasUpgrade($testlibrary));
2172     }
2174     /**
2175      * Data provider for test_libraryHasUpgrade().
2176      *
2177      * @return array
2178      */
2179     public function test_libraryHasUpgrade_provider(): array {
2180         return [
2181             'Lower major version; Identical lower version' => [
2182                 [
2183                     ['Library', 'Lib', 2, 2],
2184                 ],
2185                 [
2186                     'machineName' => 'Library',
2187                     'majorVersion' => 1,
2188                     'minorVersion' => 2
2189                 ],
2190                 true,
2191             ],
2192             'Major version identical; Lower minor version' => [
2193                 [
2194                     ['Library', 'Lib', 2, 2],
2195                 ],
2196                 [
2197                     'machineName' => 'Library',
2198                     'majorVersion' => 2,
2199                     'minorVersion' => 1
2200                 ],
2201                 true,
2202             ],
2203             'Major version identical; Minor version identical' => [
2204                 [
2205                     ['Library', 'Lib', 2, 2],
2206                 ],
2207                 [
2208                     'machineName' => 'Library',
2209                     'majorVersion' => 2,
2210                     'minorVersion' => 2
2211                 ],
2212                 false,
2213             ],
2214             'Major version higher; Minor version identical' => [
2215                 [
2216                     ['Library', 'Lib', 2, 2],
2217                 ],
2218                 [
2219                     'machineName' => 'Library',
2220                     'majorVersion' => 3,
2221                     'minorVersion' => 2
2222                 ],
2223                 false,
2224             ],
2225             'Major version identical; Minor version newer' => [
2226                 [
2227                     ['Library', 'Lib', 2, 2],
2228                 ],
2229                 [
2230                     'machineName' => 'Library',
2231                     'majorVersion' => 2,
2232                     'minorVersion' => 4
2233                 ],
2234                 false,
2235             ]
2236         ];
2237     }
2240     /**
2241      * Test the behaviour of get_latest_library_version().
2242      */
2243     public function test_get_latest_library_version() {
2244         global $DB;
2246         $this->resetAfterTest();
2248         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2249         // Create a library record.
2250         $machinename = 'TestLibrary';
2251         $lib1 = $generator->create_library_record($machinename, 'Test', 1, 1, 2);
2252         $lib2 = $generator->create_library_record($machinename, 'Test', 1, 2, 1);
2254         $content = array(
2255             'params' => json_encode(['param1' => 'Test']),
2256             'library' => array(
2257                 'libraryId' => 0,
2258                 'machineName' => 'TestLibrary',
2259             ),
2260             'disable' => 8
2261         );
2263         // Get the latest id (at this point, should be lib2).
2264         $latestlib = $this->framework->get_latest_library_version($machinename);
2265         $this->assertEquals($lib2->id, $latestlib->id);
2267         // Get the latest id (at this point, should be lib3).
2268         $lib3 = $generator->create_library_record($machinename, 'Test', 2, 1, 0);
2269         $latestlib = $this->framework->get_latest_library_version($machinename);
2270         $this->assertEquals($lib3->id, $latestlib->id);
2272         // Get the latest id (at this point, should be still lib3).
2273         $lib4 = $generator->create_library_record($machinename, 'Test', 1, 1, 3);
2274         $latestlib = $this->framework->get_latest_library_version($machinename);
2275         $this->assertEquals($lib3->id, $latestlib->id);
2277         // Get the latest id (at this point, should be lib5).
2278         $lib5 = $generator->create_library_record($machinename, 'Test', 2, 1, 6);
2279         $latestlib = $this->framework->get_latest_library_version($machinename);
2280         $this->assertEquals($lib5->id, $latestlib->id);
2281     }