Merge branch 'MDL-69813' of https://github.com/paulholden/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 use core_collator;
30 /**
31  *
32  * Test class covering the H5PFrameworkInterface interface implementation.
33  *
34  * @package    core_h5p
35  * @copyright  2019 Mihail Geshoski <mihail@moodle.com>
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  * @runTestsInSeparateProcesses
38  */
39 class framework_testcase extends \advanced_testcase {
41     /** @var \core_h5p\framework */
42     private $framework;
44     /**
45      * Set up function for tests.
46      */
47     public function setUp() {
48         $factory = new \core_h5p\factory();
49         $this->framework = $factory->get_framework();
50     }
52     /**
53      * Test the behaviour of getPlatformInfo().
54      */
55     public function test_getPlatformInfo() {
56         global $CFG;
58         $platforminfo = $this->framework->getPlatformInfo();
60         $expected = array(
61             'name' => 'Moodle',
62             'version' => $CFG->version,
63             'h5pVersion' => $CFG->version
64         );
66         $this->assertEquals($expected, $platforminfo);
67     }
69     /**
70      * Test the behaviour of fetchExternalData() when the store path is not defined.
71      *
72      * This test is intensive and requires downloading content of an external file,
73      * therefore it might take longer time to execute.
74      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
75      */
76     public function test_fetchExternalData_no_path_defined() {
78         if (!PHPUNIT_LONGTEST) {
79             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
80         }
82         $this->resetAfterTest();
84         $library = 'H5P.Accordion';
85         // Provide a valid URL to an external H5P content.
86         $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
88         // Test fetching an external H5P content without defining a path to where the file should be stored.
89         $data = $this->framework->fetchExternalData($url, null, true);
91         // The response should not be empty and return true if the file was successfully downloaded.
92         $this->assertNotEmpty($data);
93         $this->assertTrue($data);
95         $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
96         // The uploaded file should exist on the filesystem.
97         $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
98     }
100     /**
101      * Test the behaviour of fetchExternalData() when the store path is defined.
102      *
103      * This test is intensive and requires downloading content of an external file,
104      * therefore it might take longer time to execute.
105      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
106      */
107     public function test_fetchExternalData_path_defined() {
108         global $CFG;
110         if (!PHPUNIT_LONGTEST) {
111             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
112         }
114         $this->resetAfterTest();
116         $library = 'H5P.Accordion';
117         // Provide a valid URL to an external H5P content.
118         $url = $this->getExternalTestFileUrl('/'.$library.'.h5p');
120         $h5pfolderpath = $CFG->tempdir . uniqid('/h5p-');
122         $data = $this->framework->fetchExternalData($url, null, true, $h5pfolderpath . '.h5p');
124         // The response should not be empty and return true if the content has been successfully saved to a file.
125         $this->assertNotEmpty($data);
126         $this->assertTrue($data);
128         // The uploaded file should exist on the filesystem.
129         $this->assertTrue(file_exists($h5pfolderpath . '.h5p'));
130     }
132     /**
133      * Test the behaviour of fetchExternalData() when the URL is pointing to an external file that is
134      * not an h5p content.
135      *
136      * This test is intensive and requires downloading content of an external file,
137      * therefore it might take longer time to execute.
138      * In order to execute this test PHPUNIT_LONGTEST should be set to true in phpunit.xml or directly in config.php.
139      */
140     public function test_fetchExternalData_url_not_h5p() {
142         if (!PHPUNIT_LONGTEST) {
143             // This test is intensive and requires downloading the content of an external file.
144             $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
145         }
147         $this->resetAfterTest();
149         // Provide an URL to an external file that is not an H5P content file.
150         $url = $this->getExternalTestFileUrl('/h5pcontenttypes.json');
152         $data = $this->framework->fetchExternalData($url, null, true);
154         // The response should not be empty and return true if the content has been successfully saved to a file.
155         $this->assertNotEmpty($data);
156         $this->assertTrue($data);
158         // The uploaded file should exist on the filesystem with it's original extension.
159         // NOTE: The file would be later validated by the H5P Validator.
160         $h5pfolderpath = $this->framework->getUploadedH5pFolderPath();
161         $this->assertTrue(file_exists($h5pfolderpath . '.json'));
162     }
164     /**
165      * Test the behaviour of fetchExternalData() when the URL is invalid.
166      */
167     public function test_fetchExternalData_url_invalid() {
168         // Provide an invalid URL to an external file.
169         $url = "someprotocol://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
171         $data = $this->framework->fetchExternalData($url, null, true);
173         // The response should be empty.
174         $this->assertEmpty($data);
175     }
177     /**
178      * Test the behaviour of 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         // Ensure the addons array is consistently ordered before asserting their contents.
476         core_collator::asort_array_of_arrays_by_key($addons, 'machineName');
477         [$addonone, $addontwo] = array_values($addons);
479         // Make sure the version 1.3 is the latest 'Library' addon version.
480         $this->assertEquals('Library', $addonone['machineName']);
481         $this->assertEquals(1, $addonone['majorVersion']);
482         $this->assertEquals(3, $addonone['minorVersion']);
484         // Make sure the version 1.2 is the latest 'Library1' addon version.
485         $this->assertEquals('Library1', $addontwo['machineName']);
486         $this->assertEquals(1, $addontwo['majorVersion']);
487         $this->assertEquals(2, $addontwo['minorVersion']);
488     }
490     /**
491      * Test the behaviour of loadLibraries().
492      */
493     public function test_loadLibraries() {
494         $this->resetAfterTest();
496         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
498         // Generate h5p related data.
499         $generator->generate_h5p_data();
501         // Load all libraries.
502         $libraries = $this->framework->loadLibraries();
504         // Make sure all libraries are returned.
505         $this->assertNotEmpty($libraries);
506         $this->assertCount(6, $libraries);
507         $this->assertEquals('MainLibrary', $libraries['MainLibrary'][0]->machine_name);
508         $this->assertEquals('1', $libraries['MainLibrary'][0]->major_version);
509         $this->assertEquals('0', $libraries['MainLibrary'][0]->minor_version);
510         $this->assertEquals('1', $libraries['MainLibrary'][0]->patch_version);
511     }
513     /**
514      * Test the behaviour of test_getLibraryId() when requesting an existing machine name.
515      */
516     public function test_getLibraryId_existing_machine_name() {
517         $this->resetAfterTest();
519         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
521         // Create a library.
522         $lib = $generator->create_library_record('Library', 'Lib', 1, 1, 2);
524         // Request the library ID of the library with machine name 'Library'.
525         $libraryid = $this->framework->getLibraryId('Library');
527         // Make sure the library ID is being returned.
528         $this->assertNotFalse($libraryid);
529         $this->assertEquals($lib->id, $libraryid);
530     }
532     /**
533      * Test the behaviour of test_getLibraryId() when requesting a non-existent machine name.
534      */
535     public function test_getLibraryId_non_existent_machine_name() {
536         $this->resetAfterTest();
538         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
540         // Create a library.
541         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
543         // Request the library ID of the library with machinename => 'TestLibrary' (non-existent).
544         $libraryid = $this->framework->getLibraryId('TestLibrary');
546         // Make sure the library ID not being returned.
547         $this->assertFalse($libraryid);
548     }
550     /**
551      * Test the behaviour of test_getLibraryId() when requesting a non-existent major version.
552      */
553     public function test_getLibraryId_non_existent_major_version() {
554         $this->resetAfterTest();
556         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
558         // Create a library.
559         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
561         // Request the library ID of the library with machine name => 'Library', majorversion => 2 (non-existent).
562         $libraryid = $this->framework->getLibraryId('Library', 2);
564         // Make sure the library ID not being returned.
565         $this->assertFalse($libraryid);
566     }
568     /**
569      * Test the behaviour of test_getLibraryId() when requesting a non-existent minor version.
570      */
571     public function test_getLibraryId_non_existent_minor_version() {
572         $this->resetAfterTest();
574         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
576         // Create a library.
577         $generator->create_library_record('Library', 'Lib', 1, 1, 2);
579         // Request the library ID of the library with machine name => 'Library',
580         // majorversion => 1,  minorversion => 2 (non-existent).
581         $libraryid = $this->framework->getLibraryId('Library', 1, 2);
583         // Make sure the library ID not being returned.
584         $this->assertFalse($libraryid);
585     }
587     /**
588      * Test the behaviour of isPatchedLibrary().
589      *
590      * @dataProvider test_isPatchedLibrary_provider
591      * @param array $libraryrecords Array containing data for the library creation
592      * @param array $testlibrary Array containing the test library data
593      * @param bool $expected The expectation whether the library is patched or not
594      **/
595     public function test_isPatchedLibrary(array $libraryrecords, array $testlibrary, bool $expected): void {
596         $this->resetAfterTest();
598         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
600         foreach ($libraryrecords as $library) {
601             call_user_func_array([$generator, 'create_library_record'], $library);
602         }
604         $this->assertEquals($expected, $this->framework->isPatchedLibrary($testlibrary));
605     }
607     /**
608      * Data provider for test_isPatchedLibrary().
609      *
610      * @return array
611      */
612     public function test_isPatchedLibrary_provider(): array {
613         return [
614             'Unpatched library. No different versioning' => [
615                 [
616                     ['TestLibrary', 'Test', 1, 1, 2],
617                 ],
618                 [
619                     'machineName' => 'TestLibrary',
620                     'majorVersion' => 1,
621                     'minorVersion' => 1,
622                     'patchVersion' => 2
623                 ],
624                 false,
625             ],
626             'Major version identical; Minor version identical; Patch version newer' => [
627                 [
628                     ['TestLibrary', 'Test', 1, 1, 2],
629                 ],
630                 [
631                     'machineName' => 'TestLibrary',
632                     'majorVersion' => 1,
633                     'minorVersion' => 1,
634                     'patchVersion' => 3
635                 ],
636                 true,
637             ],
638             'Major version identical; Minor version newer; Patch version newer' => [
639                 [
640                     ['TestLibrary', 'Test', 1, 1, 2],
641                 ],
642                 [
643                     'machineName' => 'TestLibrary',
644                     'majorVersion' => 1,
645                     'minorVersion' => 2,
646                     'patchVersion' => 3
647                 ],
648                 false,
649             ],
650             'Major version identical; Minor version identical; Patch version older' => [
651                 [
652                     ['TestLibrary', 'Test', 1, 1, 2],
653                 ],
654                 [
655                     'machineName' => 'TestLibrary',
656                     'majorVersion' => 1,
657                     'minorVersion' => 1,
658                     'patchVersion' => 1
659                 ],
660                 false,
661             ],
662             'Major version identical; Minor version newer; Patch version older' => [
663                 [
664                     ['TestLibrary', 'Test', 1, 1, 2],
665                 ],
666                 [
667                     'machineName' => 'TestLibrary',
668                     'majorVersion' => 1,
669                     'minorVersion' => 2,
670                     'patchVersion' => 1
671                 ],
672                 false,
673             ],
674             'Major version newer; Minor version identical; Patch version older' => [
675                 [
676                     ['TestLibrary', 'Test', 1, 1, 2],
677                 ],
678                 [
679                     'machineName' => 'TestLibrary',
680                     'majorVersion' => 2,
681                     'minorVersion' => 1,
682                     'patchVersion' => 1
683                 ],
684                 false,
685             ],
686             'Major version newer; Minor version identical; Patch version newer' => [
687                 [
688                     ['TestLibrary', 'Test', 1, 1, 2],
689                 ],
690                 [
691                     'machineName' => 'TestLibrary',
692                     'majorVersion' => 2,
693                     'minorVersion' => 1,
694                     'patchVersion' => 3
695                 ],
696                 false,
697             ],
699             'Major version older; Minor version identical; Patch version older' => [
700                 [
701                     ['TestLibrary', 'Test', 1, 1, 2],
702                 ],
703                 [
704                     'machineName' => 'TestLibrary',
705                     'majorVersion' => 0,
706                     'minorVersion' => 1,
707                     'patchVersion' => 1
708                 ],
709                 false,
710             ],
711             'Major version older; Minor version identical; Patch version newer' => [
712                 [
713                     ['TestLibrary', 'Test', 1, 1, 2],
714                 ],
715                 [
716                     'machineName' => 'TestLibrary',
717                     'majorVersion' => 0,
718                     'minorVersion' => 1,
719                     'patchVersion' => 3
720                 ],
721                 false,
722             ],
723         ];
724     }
726     /**
727      * Test the behaviour of isInDevMode().
728      */
729     public function test_isInDevMode() {
730         $isdevmode = $this->framework->isInDevMode();
732         $this->assertFalse($isdevmode);
733     }
735     /**
736      * Test the behaviour of mayUpdateLibraries().
737      */
738     public function test_mayUpdateLibraries(): void {
739         global $DB;
741         $this->resetAfterTest();
743         // Create some users.
744         $contextsys = \context_system::instance();
745         $user = $this->getDataGenerator()->create_user();
746         $admin = get_admin();
747         $managerrole = $DB->get_record('role', ['shortname' => 'manager'], '*', MUST_EXIST);
748         $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST);
749         $manager = $this->getDataGenerator()->create_user();
750         role_assign($managerrole->id, $manager->id, $contextsys);
752         // Create a course with a label and enrol the user.
753         $course = $this->getDataGenerator()->create_course();
754         $label = $this->getDataGenerator()->create_module('label', ['course' => $course->id]);
755         list(, $labelcm) = get_course_and_cm_from_instance($label->id, 'label');
756         $contextlabel = \context_module::instance($labelcm->id);
757         $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
759         // Create the .h5p file.
760         $path = __DIR__ . '/fixtures/h5ptest.zip';
762         // Admin and manager should have permission to update libraries.
763         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextsys);
764         $this->framework->set_file($file);
765         $mayupdatelib = $this->framework->mayUpdateLibraries();
766         $this->assertTrue($mayupdatelib);
768         $file = helper::create_fake_stored_file_from_path($path, $manager->id, $contextsys);
769         $this->framework->set_file($file);
770         $mayupdatelib = $this->framework->mayUpdateLibraries();
771         $this->assertTrue($mayupdatelib);
773         // By default, normal user hasn't permission to update libraries (in both contexts, system and module label).
774         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
775         $this->framework->set_file($file);
776         $mayupdatelib = $this->framework->mayUpdateLibraries();
777         $this->assertFalse($mayupdatelib);
779         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
780         $this->framework->set_file($file);
781         $mayupdatelib = $this->framework->mayUpdateLibraries();
782         $this->assertFalse($mayupdatelib);
784         // If the current user (admin) can update libraries, the method should return true (even if the file userid hasn't the
785         // required capabilility in the file context).
786         $file = helper::create_fake_stored_file_from_path($path, $admin->id, $contextlabel);
787         $this->framework->set_file($file);
788         $mayupdatelib = $this->framework->mayUpdateLibraries();
789         $this->assertTrue($mayupdatelib);
791         // If the update capability is assigned to the user, they should be able to update the libraries (only in the context
792         // where the capability has been assigned).
793         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextlabel);
794         $this->framework->set_file($file);
795         $mayupdatelib = $this->framework->mayUpdateLibraries();
796         $this->assertFalse($mayupdatelib);
797         assign_capability('moodle/h5p:updatelibraries', CAP_ALLOW, $studentrole->id, $contextlabel);
798         $mayupdatelib = $this->framework->mayUpdateLibraries();
799         $this->assertTrue($mayupdatelib);
800         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextsys);
801         $this->framework->set_file($file);
802         $mayupdatelib = $this->framework->mayUpdateLibraries();
803         $this->assertFalse($mayupdatelib);
804     }
806     /**
807      * Test the behaviour of get_file() and set_file().
808      */
809     public function test_get_file(): void {
810         $this->resetAfterTest();
812         // Create some users.
813         $contextsys = \context_system::instance();
814         $user = $this->getDataGenerator()->create_user();
816         // The H5P file.
817         $path = __DIR__ . '/fixtures/h5ptest.zip';
819         // An error should be raised when it's called before initialitzing it.
820         $this->expectException('coding_exception');
821         $this->expectExceptionMessage('Using get_file() before file is set');
822         $this->framework->get_file();
824         // Check the value when only path and user are set.
825         $file = helper::create_fake_stored_file_from_path($path, $user->id);
826         $this->framework->set_file($file);
827         $file = $this->framework->get_file();
828         $this->assertEquals($user->id, $$file->get_userid());
829         $this->assertEquals($contextsys->id, $file->get_contextid());
831         // Check the value when also the context is set.
832         $course = $this->getDataGenerator()->create_course();
833         $contextcourse = \context_course::instance($course->id);
834         $file = helper::create_fake_stored_file_from_path($path, $user->id, $contextcourse);
835         $this->framework->set_file($file);
836         $file = $this->framework->get_file();
837         $this->assertEquals($user->id, $$file->get_userid());
838         $this->assertEquals($contextcourse->id, $file->get_contextid());
839     }
841     /**
842      * Test the behaviour of saveLibraryData() when saving data for a new library.
843      */
844     public function test_saveLibraryData_new_library() {
845         global $DB;
847         $this->resetAfterTest();
849         $librarydata = array(
850             'title' => 'Test',
851             'machineName' => 'TestLibrary',
852             'majorVersion' => '1',
853             'minorVersion' => '0',
854             'patchVersion' => '2',
855             'runnable' => 1,
856             'fullscreen' => 1,
857             'preloadedJs' => array(
858                 array(
859                     'path' => 'js/name.min.js'
860                 )
861             ),
862             'preloadedCss' => array(
863                 array(
864                     'path' => 'css/name.css'
865                 )
866             ),
867             'dropLibraryCss' => array(
868                 array(
869                     'machineName' => 'Name2'
870                 )
871             )
872         );
874         // Create a new library.
875         $this->framework->saveLibraryData($librarydata);
877         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
879         // Make sure the library data was properly saved.
880         $this->assertNotEmpty($library);
881         $this->assertNotEmpty($librarydata['libraryId']);
882         $this->assertEquals($librarydata['title'], $library->title);
883         $this->assertEquals($librarydata['machineName'], $library->machinename);
884         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
885         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
886         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
887         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
888         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
889         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
890     }
892     /**
893      * Test the behaviour of saveLibraryData() when saving (updating) data for an existing library.
894      */
895     public function test_saveLibraryData_existing_library() {
896         global $DB;
898         $this->resetAfterTest();
900         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
902         // Create a library record.
903         $library = $generator->create_library_record('TestLibrary', 'Test', 1, 0, 2);
905         $librarydata = array(
906             'libraryId' => $library->id,
907             'title' => 'Test1',
908             'machineName' => 'TestLibrary',
909             'majorVersion' => '1',
910             'minorVersion' => '2',
911             'patchVersion' => '2',
912             'runnable' => 1,
913             'fullscreen' => 1,
914             'preloadedJs' => array(
915                 array(
916                     'path' => 'js/name.min.js'
917                 )
918             ),
919             'preloadedCss' => array(
920                 array(
921                     'path' => 'css/name.css'
922                 )
923             ),
924             'dropLibraryCss' => array(
925                 array(
926                     'machineName' => 'Name2'
927                 )
928             )
929         );
931         // Update the library.
932         $this->framework->saveLibraryData($librarydata, false);
934         $library = $DB->get_record('h5p_libraries', ['machinename' => $librarydata['machineName']]);
936         // Make sure the library data was properly updated.
937         $this->assertNotEmpty($library);
938         $this->assertNotEmpty($librarydata['libraryId']);
939         $this->assertEquals($librarydata['title'], $library->title);
940         $this->assertEquals($librarydata['machineName'], $library->machinename);
941         $this->assertEquals($librarydata['majorVersion'], $library->majorversion);
942         $this->assertEquals($librarydata['minorVersion'], $library->minorversion);
943         $this->assertEquals($librarydata['patchVersion'], $library->patchversion);
944         $this->assertEquals($librarydata['preloadedJs'][0]['path'], $library->preloadedjs);
945         $this->assertEquals($librarydata['preloadedCss'][0]['path'], $library->preloadedcss);
946         $this->assertEquals($librarydata['dropLibraryCss'][0]['machineName'], $library->droplibrarycss);
947     }
949     /**
950      * Test the behaviour of insertContent().
951      */
952     public function test_insertContent() {
953         global $DB;
955         $this->resetAfterTest();
957         $content = array(
958             'params' => json_encode(['param1' => 'Test']),
959             'library' => array(
960                 'libraryId' => 1
961             ),
962             'disable' => 8
963         );
965         // Insert h5p content.
966         $contentid = $this->framework->insertContent($content);
968         // Get the entered content from the db.
969         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
971         // Make sure the h5p content was properly inserted.
972         $this->assertNotEmpty($dbcontent);
973         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
974         $this->assertEquals($content['library']['libraryId'], $dbcontent->mainlibraryid);
975         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
976     }
978     /**
979      * Test the behaviour of insertContent().
980      */
981     public function test_insertContent_latestlibrary() {
982         global $DB;
984         $this->resetAfterTest();
986         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
987         // Create a library record.
988         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
990         $content = array(
991             'params' => json_encode(['param1' => 'Test']),
992             'library' => array(
993                 'libraryId' => 0,
994                 'machineName' => 'TestLibrary',
995             ),
996             'disable' => 8
997         );
999         // Insert h5p content.
1000         $contentid = $this->framework->insertContent($content);
1002         // Get the entered content from the db.
1003         $dbcontent = $DB->get_record('h5p', ['id' => $contentid]);
1005         // Make sure the h5p content was properly inserted.
1006         $this->assertNotEmpty($dbcontent);
1007         $this->assertEquals($content['params'], $dbcontent->jsoncontent);
1008         $this->assertEquals($content['disable'], $dbcontent->displayoptions);
1009         // As the libraryId was empty, the latest library has been used.
1010         $this->assertEquals($lib->id, $dbcontent->mainlibraryid);
1011     }
1013     /**
1014      * Test the behaviour of updateContent().
1015      */
1016     public function test_updateContent() {
1017         global $DB;
1019         $this->resetAfterTest();
1021         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1023         // Create a library record.
1024         $lib = $generator->create_library_record('TestLibrary', 'Test', 1, 1, 2);
1026         // Create an h5p content with 'TestLibrary' as it's main library.
1027         $contentid = $generator->create_h5p_record($lib->id);
1029         $content = array(
1030             'id' => $contentid,
1031             'params' => json_encode(['param2' => 'Test2']),
1032             'library' => array(
1033                 'libraryId' => $lib->id
1034             ),
1035             'disable' => 8
1036         );
1038         // Update the h5p content.
1039         $this->framework->updateContent($content);
1041         $h5pcontent = $DB->get_record('h5p', ['id' => $contentid]);
1043         // Make sure the h5p content was properly updated.
1044         $this->assertNotEmpty($h5pcontent);
1045         $this->assertEquals($content['params'], $h5pcontent->jsoncontent);
1046         $this->assertEquals($content['library']['libraryId'], $h5pcontent->mainlibraryid);
1047         $this->assertEquals($content['disable'], $h5pcontent->displayoptions);
1048     }
1050     /**
1051      * Test the behaviour of saveLibraryDependencies().
1052      */
1053     public function test_saveLibraryDependencies() {
1054         global $DB;
1056         $this->resetAfterTest();
1058         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1060         // Create a library 'Library'.
1061         $library = $generator->create_library_record('Library', 'Title');
1062         // Create a library 'DependencyLibrary1'.
1063         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1064         // Create a library 'DependencyLibrary2'.
1065         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1067         $dependencies = array(
1068             array(
1069                 'machineName' => $dependency1->machinename,
1070                 'majorVersion' => $dependency1->majorversion,
1071                 'minorVersion' => $dependency1->minorversion
1072             ),
1073             array(
1074                 'machineName' => $dependency2->machinename,
1075                 'majorVersion' => $dependency2->majorversion,
1076                 'minorVersion' => $dependency2->minorversion
1077             ),
1078         );
1080         // Set 'DependencyLibrary1' and 'DependencyLibrary2' as library dependencies of 'Library'.
1081         $this->framework->saveLibraryDependencies($library->id, $dependencies, 'preloaded');
1083         $libdependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library->id], 'id ASC');
1085         // Make sure the library dependencies for 'Library' are properly set.
1086         $this->assertEquals(2, count($libdependencies));
1087         $this->assertEquals($dependency1->id, reset($libdependencies)->requiredlibraryid);
1088         $this->assertEquals($dependency2->id, end($libdependencies)->requiredlibraryid);
1089     }
1091     /**
1092      * Test the behaviour of deleteContentData().
1093      */
1094     public function test_deleteContentData() {
1095         global $DB;
1097         $this->resetAfterTest();
1099         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1101         // Generate some h5p related data.
1102         $data = $generator->generate_h5p_data();
1103         $h5pid = $data->h5pcontent->h5pid;
1105         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1106         // Make sure the particular h5p content exists in the DB.
1107         $this->assertNotEmpty($h5pcontent);
1109         // Get the h5p content libraries from the DB.
1110         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1112         // Make sure the content libraries exists in the DB.
1113         $this->assertNotEmpty($h5pcontentlibraries);
1114         $this->assertCount(5, $h5pcontentlibraries);
1116         // Delete the h5p content and it's related data.
1117         $this->framework->deleteContentData($h5pid);
1119         $h5pcontent = $DB->get_record('h5p', ['id' => $h5pid]);
1120         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1122         // The particular h5p content should no longer exist in the db.
1123         $this->assertEmpty($h5pcontent);
1124         // The particular content libraries should no longer exist in the db.
1125         $this->assertEmpty($h5pcontentlibraries);
1126     }
1128     /**
1129      * Test the behaviour of deleteLibraryUsage().
1130      */
1131     public function test_deleteLibraryUsage() {
1132         global $DB;
1134         $this->resetAfterTest();
1136         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1138         // Generate some h5p related data.
1139         $data = $generator->generate_h5p_data();
1140         $h5pid = $data->h5pcontent->h5pid;
1142         // Get the h5p content libraries from the DB.
1143         $h5pcontentlibraries = $DB->get_records('h5p_contents_libraries', ['h5pid' => $h5pid]);
1145         // The particular h5p content should have 5 content libraries.
1146         $this->assertNotEmpty($h5pcontentlibraries);
1147         $this->assertCount(5, $h5pcontentlibraries);
1149         // Delete the h5p content and it's related data.
1150         $this->framework->deleteLibraryUsage($h5pid);
1152         // Get the h5p content libraries from the DB.
1153         $h5pcontentlibraries = $DB->get_record('h5p_contents_libraries', ['h5pid' => $h5pid]);
1155         // The particular h5p content libraries should no longer exist in the db.
1156         $this->assertEmpty($h5pcontentlibraries);
1157     }
1159     /**
1160      * Test the behaviour of test_saveLibraryUsage().
1161      */
1162     public function test_saveLibraryUsage() {
1163         global $DB;
1165         $this->resetAfterTest();
1167         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1169         // Create a library 'Library'.
1170         $library = $generator->create_library_record('Library', 'Title');
1171         // Create a library 'DependencyLibrary1'.
1172         $dependency1 = $generator->create_library_record('DependencyLibrary1', 'DependencyTitle1');
1173         // Create a library 'DependencyLibrary2'.
1174         $dependency2 = $generator->create_library_record('DependencyLibrary2', 'DependencyTitle2');
1175         // Create an h5p content with 'Library' as it's main library.
1176         $contentid = $generator->create_h5p_record($library->id);
1178         $dependencies = array(
1179             array(
1180                 'library' => array(
1181                     'libraryId' => $dependency1->id,
1182                     'machineName' => $dependency1->machinename,
1183                     'dropLibraryCss' => $dependency1->droplibrarycss
1184                 ),
1185                 'type' => 'preloaded',
1186                 'weight' => 1
1187             ),
1188             array(
1189                 'library' => array(
1190                     'libraryId' => $dependency2->id,
1191                     'machineName' => $dependency2->machinename,
1192                     'dropLibraryCss' => $dependency2->droplibrarycss
1193                 ),
1194                 'type' => 'preloaded',
1195                 'weight' => 2
1196             ),
1197         );
1199         // Save 'DependencyLibrary1' and 'DependencyLibrary2' as h5p content libraries.
1200         $this->framework->saveLibraryUsage($contentid, $dependencies);
1202         // Get the h5p content libraries from the DB.
1203         $libdependencies = $DB->get_records('h5p_contents_libraries', ['h5pid' => $contentid], 'id ASC');
1205         // Make sure that 'DependencyLibrary1' and 'DependencyLibrary2' are properly set as h5p content libraries.
1206         $this->assertEquals(2, count($libdependencies));
1207         $this->assertEquals($dependency1->id, reset($libdependencies)->libraryid);
1208         $this->assertEquals($dependency2->id, end($libdependencies)->libraryid);
1209     }
1211     /**
1212      * Test the behaviour of getLibraryUsage() without skipping a particular h5p content.
1213      */
1214     public function test_getLibraryUsage_no_skip_content() {
1215         $this->resetAfterTest();
1217         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1219         // Generate h5p related data.
1220         $generateddata = $generator->generate_h5p_data();
1221         // The Id of the library 'Library1'.
1222         $library1id = $generateddata->lib1->data->id;
1223         // The Id of the library 'Library2'.
1224         $library2id = $generateddata->lib2->data->id;
1225         // The Id of the library 'Library5'.
1226         $library5id = $generateddata->lib5->data->id;
1228         // Get the library usage for 'Library1' (do not skip content).
1229         $data = $this->framework->getLibraryUsage($library1id);
1231         $expected = array(
1232             'content' => 1,
1233             'libraries' => 1
1234         );
1236         // Make sure 'Library1' is used by 1 content and is a dependency to 1 library.
1237         $this->assertEquals($expected, $data);
1239         // Get the library usage for 'Library2' (do not skip content).
1240         $data = $this->framework->getLibraryUsage($library2id);
1242         $expected = array(
1243             'content' => 1,
1244             'libraries' => 2,
1245         );
1247         // Make sure 'Library2' is used by 1 content and is a dependency to 2 libraries.
1248         $this->assertEquals($expected, $data);
1250          // Get the library usage for 'Library5' (do not skip content).
1251         $data = $this->framework->getLibraryUsage($library5id);
1253         $expected = array(
1254             'content' => 0,
1255             'libraries' => 1,
1256         );
1258         // Make sure 'Library5' is not used by any content and is a dependency to 1 library.
1259         $this->assertEquals($expected, $data);
1260     }
1262     /**
1263      * Test the behaviour of getLibraryUsage() when skipping a particular content.
1264      */
1265     public function test_getLibraryUsage_skip_content() {
1266         $this->resetAfterTest();
1268         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1270         // Generate h5p related data.
1271         $generateddata = $generator->generate_h5p_data();
1272         // The Id of the library 'Library1'.
1273         $library1id = $generateddata->lib1->data->id;
1275         // Get the library usage for 'Library1' (skip content).
1276         $data = $this->framework->getLibraryUsage($library1id, true);
1277         $expected = array(
1278             'content' => -1,
1279             'libraries' => 1,
1280         );
1282         // Make sure 'Library1' is a dependency to 1 library.
1283         $this->assertEquals($expected, $data);
1284     }
1286     /**
1287      * Test the behaviour of loadLibrary() when requesting an existing library.
1288      */
1289     public function test_loadLibrary_existing_library() {
1290         $this->resetAfterTest();
1292         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1294         // Generate h5p related data.
1295         $generateddata = $generator->generate_h5p_data();
1296         // The library data of 'Library1'.
1297         $library1 = $generateddata->lib1->data;
1298         // The library data of 'Library5'.
1299         $library5 = $generateddata->lib5->data;
1301         // The preloaded dependencies.
1302         $preloadeddependencies = array();
1304         foreach ($generateddata->lib1->dependencies as $preloadeddependency) {
1305             $preloadeddependencies[] = array(
1306                 'machineName' => $preloadeddependency->machinename,
1307                 'majorVersion' => $preloadeddependency->majorversion,
1308                 'minorVersion' => $preloadeddependency->minorversion
1309             );
1310         }
1312         // Create a dynamic dependency.
1313         $generator->create_library_dependency_record($library1->id, $library5->id, 'dynamic');
1315         $dynamicdependencies[] = array(
1316             'machineName' => $library5->machinename,
1317             'majorVersion' => $library5->majorversion,
1318             'minorVersion' => $library5->minorversion
1319         );
1321         // Load 'Library1' data.
1322         $data = $this->framework->loadLibrary($library1->machinename, $library1->majorversion,
1323             $library1->minorversion);
1325         $expected = array(
1326             'libraryId' => $library1->id,
1327             'title' => $library1->title,
1328             'machineName' => $library1->machinename,
1329             'majorVersion' => $library1->majorversion,
1330             'minorVersion' => $library1->minorversion,
1331             'patchVersion' => $library1->patchversion,
1332             'runnable' => $library1->runnable,
1333             'fullscreen' => $library1->fullscreen,
1334             'embedTypes' => $library1->embedtypes,
1335             'preloadedJs' => $library1->preloadedjs,
1336             'preloadedCss' => $library1->preloadedcss,
1337             'dropLibraryCss' => $library1->droplibrarycss,
1338             'semantics' => $library1->semantics,
1339             'preloadedDependencies' => $preloadeddependencies,
1340             'dynamicDependencies' => $dynamicdependencies
1341         );
1343         // Make sure the 'Library1' data is properly loaded.
1344         $this->assertEquals($expected, $data);
1345     }
1347     /**
1348      * Test the behaviour of loadLibrary() when requesting a non-existent library.
1349      */
1350     public function test_loadLibrary_non_existent_library() {
1351         $this->resetAfterTest();
1353         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1355         // Generate h5p related data.
1356         $generator->generate_h5p_data();
1358         // Attempt to load a non-existent library.
1359         $data = $this->framework->loadLibrary('MissingLibrary', 1, 2);
1361         // Make sure nothing is loaded.
1362         $this->assertFalse($data);
1363     }
1365     /**
1366      * Test the behaviour of loadLibrarySemantics().
1367      *
1368      * @dataProvider test_loadLibrarySemantics_provider
1369      * @param array $libraryrecords Array containing data for the library creation
1370      * @param array $testlibrary Array containing the test library data
1371      * @param string $expected The expected semantics value
1372      **/
1373     public function test_loadLibrarySemantics(array $libraryrecords, array $testlibrary, string $expected): void {
1374         $this->resetAfterTest();
1376         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1378         foreach ($libraryrecords as $library) {
1379             call_user_func_array([$generator, 'create_library_record'], $library);
1380         }
1382         $this->assertEquals($expected, $this->framework->loadLibrarySemantics(
1383             $testlibrary['machinename'], $testlibrary['majorversion'], $testlibrary['minorversion']));
1384     }
1386     /**
1387      * Data provider for test_loadLibrarySemantics().
1388      *
1389      * @return array
1390      */
1391     public function test_loadLibrarySemantics_provider(): array {
1393         $semantics = json_encode(
1394             [
1395                 'type' => 'text',
1396                 'name' => 'text',
1397                 'label' => 'Plain text',
1398                 'description' => 'Please add some text'
1399             ]
1400         );
1402         return [
1403             'Library with semantics' => [
1404                 [
1405                     ['Library1', 'Lib1', 1, 1, 2, $semantics],
1406                 ],
1407                 [
1408                     'machinename' => 'Library1',
1409                     'majorversion' => 1,
1410                     'minorversion' => 1
1411                 ],
1412                 $semantics,
1413             ],
1414             'Library without semantics' => [
1415                 [
1416                     ['Library2', 'Lib2', 1, 2, 2, ''],
1417                 ],
1418                 [
1419                     'machinename' => 'Library2',
1420                     'majorversion' => 1,
1421                     'minorversion' => 2
1422                 ],
1423                 '',
1424             ]
1425         ];
1426     }
1428     /**
1429      * Test the behaviour of alterLibrarySemantics().
1430      */
1431     public function test_alterLibrarySemantics() {
1432         global $DB;
1434         $this->resetAfterTest();
1436         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1438         $semantics = json_encode(
1439             array(
1440                 'type' => 'text',
1441                 'name' => 'text',
1442                 'label' => 'Plain text',
1443                 'description' => 'Please add some text'
1444             )
1445         );
1447         // Create a library 'Library1' with semantics.
1448         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2, $semantics);
1450         $updatedsemantics = array(
1451             'type' => 'text',
1452             'name' => 'updated text',
1453             'label' => 'Updated text',
1454             'description' => 'Please add some text'
1455         );
1457         // Alter the semantics of 'Library1'.
1458         $this->framework->alterLibrarySemantics($updatedsemantics, 'Library1', 1, 1);
1460         // Get the semantics of 'Library1' from the DB.
1461         $currentsemantics = $DB->get_field('h5p_libraries', 'semantics', array('id' => $library1->id));
1463         // The semantics for Library1 shouldn't be updated.
1464         $this->assertEquals($semantics, $currentsemantics);
1465     }
1467     /**
1468      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1469      * dependencies of an existing library.
1470      */
1471     public function test_deleteLibraryDependencies_existing_library() {
1472         global $DB;
1474         $this->resetAfterTest();
1476         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1478         // Generate h5p related data.
1479         $data = $generator->generate_h5p_data();
1480         // The data of the library 'Library1'.
1481         $library1 = $data->lib1->data;
1483         // Get the dependencies of 'Library1'.
1484         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1485         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1486         $this->assertCount(3, $dependencies);
1488         // Delete the dependencies of 'Library1'.
1489         $this->framework->deleteLibraryDependencies($library1->id);
1491         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1492         // The 'Library1' should have 0 dependencies.
1493         $this->assertCount(0, $dependencies);
1494     }
1496     /**
1497      * Test the behaviour of deleteLibraryDependencies() when requesting to delete the
1498      * dependencies of a non-existent library.
1499      */
1500     public function test_deleteLibraryDependencies_non_existent_library() {
1501         global $DB;
1503         $this->resetAfterTest();
1505         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1507         // Generate h5p related data.
1508         $data = $generator->generate_h5p_data();
1509         // The data of the library 'Library1'.
1510         $library1 = $data->lib1->data;
1512         // Get the dependencies of 'Library1'.
1513         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1514         // The 'Library1' should have 3 dependencies ('Library2', 'Library3', 'Library4').
1515         $this->assertCount(3, $dependencies);
1517         // Delete the dependencies of a non-existent library.
1518         $this->framework->deleteLibraryDependencies(0);
1520         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1521         // The 'Library1' should have 3 dependencies.
1522         $this->assertCount(3, $dependencies);
1523     }
1525     /**
1526      * Test the behaviour of deleteLibrary().
1527      */
1528     public function test_deleteLibrary() {
1529         global $DB;
1531         $this->resetAfterTest();
1533         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1535         // Generate h5p related data.
1536         $data = $generator->generate_h5p_data(true);
1537         // The data of the 'Library1' library.
1538         $library1 = $data->lib1->data;
1540         // Get the library dependencies of 'Library1'.
1541         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1543         // The 'Library1' should have 3 library dependencies ('Library2', 'Library3', 'Library4').
1544         $this->assertCount(3, $dependencies);
1546         // Return the created 'Library1' files.
1547         $libraryfiles = $DB->get_records('files',
1548             array(
1549                 'component' => \core_h5p\file_storage::COMPONENT,
1550                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1551                 'itemid' => $library1->id
1552             )
1553         );
1555         // The library ('Library1') should have 7 related folders/files.
1556         $this->assertCount(7, $libraryfiles);
1558         // Delete the library.
1559         $this->framework->deleteLibrary($library1);
1561         $lib1 = $DB->get_record('h5p_libraries', ['machinename' => $library1->machinename]);
1562         $dependencies = $DB->get_records('h5p_library_dependencies', ['libraryid' => $library1->id]);
1563         $libraryfiles = $DB->get_records('files',
1564             array(
1565                 'component' => \core_h5p\file_storage::COMPONENT,
1566                 'filearea' => \core_h5p\file_storage::LIBRARY_FILEAREA,
1567                 'itemid' => $library1->id
1568             )
1569         );
1571         // The 'Library1' should not exist.
1572         $this->assertEmpty($lib1);
1573         // The library ('Library1')  should have 0 dependencies.
1574         $this->assertCount(0, $dependencies);
1575         // The library (library1) should have 0 related folders/files.
1576         $this->assertCount(0, $libraryfiles);
1577     }
1579     /**
1580      * Test the behaviour of loadContent().
1581      */
1582     public function test_loadContent() {
1583         global $DB;
1585         $this->resetAfterTest();
1587         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1589         // Generate h5p related data.
1590         $data = $generator->generate_h5p_data();
1591         // The Id of the created h5p content.
1592         $h5pid = $data->h5pcontent->h5pid;
1593         // Get the h5p content data from the DB.
1594         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1595         // The data of content's main library ('MainLibrary').
1596         $mainlibrary = $data->mainlib->data;
1598         // Load the h5p content.
1599         $content = $this->framework->loadContent($h5pid);
1601         $expected = array(
1602             'id' => $h5p->id,
1603             'params' => $h5p->jsoncontent,
1604             'embedType' => 'iframe',
1605             'disable' => $h5p->displayoptions,
1606             'title' => $mainlibrary->title,
1607             'slug' => \H5PCore::slugify($mainlibrary->title) . '-' . $h5p->id,
1608             'filtered' => $h5p->filtered,
1609             'libraryId' => $mainlibrary->id,
1610             'libraryName' => $mainlibrary->machinename,
1611             'libraryMajorVersion' => $mainlibrary->majorversion,
1612             'libraryMinorVersion' => $mainlibrary->minorversion,
1613             'libraryEmbedTypes' => $mainlibrary->embedtypes,
1614             'libraryFullscreen' => $mainlibrary->fullscreen,
1615             'metadata' => '',
1616             'pathnamehash' => $h5p->pathnamehash
1617         );
1619         $params = json_decode($h5p->jsoncontent);
1620         if (empty($params->metadata)) {
1621             $params->metadata = new \stdClass();
1622         }
1623         $expected['metadata'] = $params->metadata;
1624         $expected['params'] = json_encode($params->params ?? $params);
1626         // The returned content should match the expected array.
1627         $this->assertEquals($expected, $content);
1628     }
1630     /**
1631      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1632      * without specifying the dependency type.
1633      */
1634     public function test_loadContentDependencies_no_type_defined() {
1635         $this->resetAfterTest();
1637         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1639         // Generate h5p related data.
1640         $data = $generator->generate_h5p_data();
1641         // The Id of the h5p content.
1642         $h5pid = $data->h5pcontent->h5pid;
1643         // The content dependencies.
1644         $dependencies = $data->h5pcontent->contentdependencies;
1646         // Add Library5 as a content dependency (dynamic dependency type).
1647         $library5 = $data->lib5->data;
1648         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1650         // Get all content dependencies.
1651         $contentdependencies = $this->framework->loadContentDependencies($h5pid);
1653         $expected = array();
1654         foreach ($dependencies as $dependency) {
1655             $expected[$dependency->machinename] = array(
1656                 'libraryId' => $dependency->id,
1657                 'machineName' => $dependency->machinename,
1658                 'majorVersion' => $dependency->majorversion,
1659                 'minorVersion' => $dependency->minorversion,
1660                 'patchVersion' => $dependency->patchversion,
1661                 'preloadedCss' => $dependency->preloadedcss,
1662                 'preloadedJs' => $dependency->preloadedjs,
1663                 'dropCss' => '0',
1664                 'dependencyType' => 'preloaded'
1665             );
1666         }
1668         $expected = array_merge($expected,
1669             array(
1670                 'Library5' => array(
1671                     'libraryId' => $library5->id,
1672                     'machineName' => $library5->machinename,
1673                     'majorVersion' => $library5->majorversion,
1674                     'minorVersion' => $library5->minorversion,
1675                     'patchVersion' => $library5->patchversion,
1676                     'preloadedCss' => $library5->preloadedcss,
1677                     'preloadedJs' => $library5->preloadedjs,
1678                     'dropCss' => '0',
1679                     'dependencyType' => 'dynamic'
1680                 )
1681             )
1682         );
1684         // The loaded content dependencies should return 6 libraries.
1685         $this->assertCount(6, $contentdependencies);
1686         $this->assertEquals($expected, $contentdependencies);
1687     }
1689     /**
1690      * Test the behaviour of loadContentDependencies() when requesting content dependencies
1691      * with specifying the dependency type.
1692      */
1693     public function test_loadContentDependencies_type_defined() {
1694         $this->resetAfterTest();
1696         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1698         // Generate h5p related data.
1699         $data = $generator->generate_h5p_data();
1700         // The Id of the h5p content.
1701         $h5pid = $data->h5pcontent->h5pid;
1702         // The content dependencies.
1703         $dependencies = $data->h5pcontent->contentdependencies;
1705         // Add Library5 as a content dependency (dynamic dependency type).
1706         $library5 = $data->lib5->data;
1707         $generator->create_contents_libraries_record($h5pid, $library5->id, 'dynamic');
1709         // Load all content dependencies of dependency type 'preloaded'.
1710         $preloadeddependencies = $this->framework->loadContentDependencies($h5pid, 'preloaded');
1712         $expected = array();
1713         foreach ($dependencies as $dependency) {
1714             $expected[$dependency->machinename] = array(
1715                 'libraryId' => $dependency->id,
1716                 'machineName' => $dependency->machinename,
1717                 'majorVersion' => $dependency->majorversion,
1718                 'minorVersion' => $dependency->minorversion,
1719                 'patchVersion' => $dependency->patchversion,
1720                 'preloadedCss' => $dependency->preloadedcss,
1721                 'preloadedJs' => $dependency->preloadedjs,
1722                 'dropCss' => '0',
1723                 'dependencyType' => 'preloaded'
1724             );
1725         }
1727         // The loaded content dependencies should return 5 libraries.
1728         $this->assertCount(5, $preloadeddependencies);
1729         $this->assertEquals($expected, $preloadeddependencies);
1731         // Load all content dependencies of dependency type 'dynamic'.
1732         $dynamicdependencies = $this->framework->loadContentDependencies($h5pid, 'dynamic');
1734         $expected = array(
1735             'Library5' => array(
1736                 'libraryId' => $library5->id,
1737                 'machineName' => $library5->machinename,
1738                 'majorVersion' => $library5->majorversion,
1739                 'minorVersion' => $library5->minorversion,
1740                 'patchVersion' => $library5->patchversion,
1741                 'preloadedCss' => $library5->preloadedcss,
1742                 'preloadedJs' => $library5->preloadedjs,
1743                 'dropCss' => '0',
1744                 'dependencyType' => 'dynamic'
1745             )
1746         );
1748         // The loaded content dependencies should now return 1 library.
1749         $this->assertCount(1, $dynamicdependencies);
1750         $this->assertEquals($expected, $dynamicdependencies);
1751     }
1753     /**
1754      * Test the behaviour of getOption().
1755      */
1756     public function test_getOption(): void {
1757         $this->resetAfterTest();
1759         // Get value for display_option_download.
1760         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_DOWNLOAD);
1761         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1762         $this->assertEquals($expected, $value);
1764         // Get value for display_option_embed using default value (it should be ignored).
1765         $value = $this->framework->getOption(\H5PCore::DISPLAY_OPTION_EMBED, \H5PDisplayOptionBehaviour::NEVER_SHOW);
1766         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1767         $this->assertEquals($expected, $value);
1769         // Get value for unexisting setting without default.
1770         $value = $this->framework->getOption('unexistingsetting');
1771         $expected = false;
1772         $this->assertEquals($expected, $value);
1774         // Get value for unexisting setting with default.
1775         $value = $this->framework->getOption('unexistingsetting', 'defaultvalue');
1776         $expected = 'defaultvalue';
1777         $this->assertEquals($expected, $value);
1778     }
1780     /**
1781      * Test the behaviour of setOption().
1782      */
1783     public function test_setOption(): void {
1784         $this->resetAfterTest();
1786         // Set value for 'newsetting' setting.
1787         $name = 'newsetting';
1788         $value = $this->framework->getOption($name);
1789         $this->assertEquals(false, $value);
1790         $newvalue = 'value1';
1791         $this->framework->setOption($name, $newvalue);
1792         $value = $this->framework->getOption($name);
1793         $this->assertEquals($newvalue, $value);
1795         // Set value for display_option_download and then get it again. Check it hasn't changed.
1796         $name = \H5PCore::DISPLAY_OPTION_DOWNLOAD;
1797         $newvalue = \H5PDisplayOptionBehaviour::NEVER_SHOW;
1798         $this->framework->setOption($name, $newvalue);
1799         $value = $this->framework->getOption($name);
1800         $expected = \H5PDisplayOptionBehaviour::CONTROLLED_BY_AUTHOR_DEFAULT_OFF;
1801         $this->assertEquals($expected, $value);
1802     }
1804     /**
1805      * Test the behaviour of updateContentFields().
1806      */
1807     public function test_updateContentFields() {
1808         global $DB;
1810         $this->resetAfterTest();
1812         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1814         // Create 'Library1' library.
1815         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1816         // Create 'Library2' library.
1817         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1819         // Create an h5p content with 'Library1' as it's main library.
1820         $h5pid = $generator->create_h5p_record($library1->id, 'iframe');
1822         $updatedata = array(
1823             'jsoncontent' => json_encode(['value' => 'test']),
1824             'mainlibraryid' => $library2->id
1825         );
1827         // Update h5p content fields.
1828         $this->framework->updateContentFields($h5pid, $updatedata);
1830         // Get the h5p content from the DB.
1831         $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
1833         $expected = json_encode(['value' => 'test']);
1835         // Make sure the h5p content fields are properly updated.
1836         $this->assertEquals($expected, $h5p->jsoncontent);
1837         $this->assertEquals($library2->id, $h5p->mainlibraryid);
1838     }
1840     /**
1841      * Test the behaviour of clearFilteredParameters().
1842      */
1843     public function test_clearFilteredParameters() {
1844         global $DB;
1846         $this->resetAfterTest();
1848         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1850         // Create 3 libraries.
1851         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1852         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1853         $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1855         // Create h5p content with 'Library1' as a main library.
1856         $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1857         // Create h5p content with 'Library1' as a main library.
1858         $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1859         // Create h5p content with 'Library2' as a main library.
1860         $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1861         // Create h5p content with 'Library3' as a main library.
1862         $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1864         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1865         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1866         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1867         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1869         // The filtered parameters should be present in each h5p content.
1870         $this->assertNotEmpty($h5pcontent1->filtered);
1871         $this->assertNotEmpty($h5pcontent2->filtered);
1872         $this->assertNotEmpty($h5pcontent3->filtered);
1873         $this->assertNotEmpty($h5pcontent4->filtered);
1875         // Clear the filtered parameters for contents that have library1 and library3 as
1876         // their main library.
1877         $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1879         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1880         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1881         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1882         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1884         // The filtered parameters should be still present only for the content that has
1885         // library 2 as a main library.
1886         $this->assertEmpty($h5pcontent1->filtered);
1887         $this->assertEmpty($h5pcontent2->filtered);
1888         $this->assertNotEmpty($h5pcontent3->filtered);
1889         $this->assertEmpty($h5pcontent4->filtered);
1890     }
1892     /**
1893      * Test the behaviour of getNumNotFiltered().
1894      */
1895     public function test_getNumNotFiltered() {
1896         global $DB;
1898         $this->resetAfterTest();
1900         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1902         // Create 3 libraries.
1903         $library1 = $generator->create_library_record('Library1', 'Lib1', 1, 1, 2);
1904         $library2 = $generator->create_library_record('Library2', 'Lib2', 1, 1, 2);
1905         $library3 = $generator->create_library_record('Library3', 'Lib3', 1, 1, 2);
1907         // Create h5p content with library1 as a main library.
1908         $h5pcontentid1 = $generator->create_h5p_record($library1->id);
1909         // Create h5p content with library1 as a main library.
1910         $h5pcontentid2 = $generator->create_h5p_record($library1->id);
1911         // Create h5p content with library2 as a main library.
1912         $h5pcontentid3 = $generator->create_h5p_record($library2->id);
1913         // Create h5p content with library3 as a main library.
1914         $h5pcontentid4 = $generator->create_h5p_record($library3->id);
1916         $h5pcontent1 = $DB->get_record('h5p', ['id' => $h5pcontentid1]);
1917         $h5pcontent2 = $DB->get_record('h5p', ['id' => $h5pcontentid2]);
1918         $h5pcontent3 = $DB->get_record('h5p', ['id' => $h5pcontentid3]);
1919         $h5pcontent4 = $DB->get_record('h5p', ['id' => $h5pcontentid4]);
1921         // The filtered parameters should be present in each h5p content.
1922         $this->assertNotEmpty($h5pcontent1->filtered);
1923         $this->assertNotEmpty($h5pcontent2->filtered);
1924         $this->assertNotEmpty($h5pcontent3->filtered);
1925         $this->assertNotEmpty($h5pcontent4->filtered);
1927         // Clear the filtered parameters for contents that have library1 and library3 as
1928         // their main library.
1929         $this->framework->clearFilteredParameters([$library1->id, $library3->id]);
1931         $countnotfiltered = $this->framework->getNumNotFiltered();
1933         // 3 contents don't have their parameters filtered.
1934         $this->assertEquals(3, $countnotfiltered);
1935     }
1937     /**
1938      * Test the behaviour of getNumContent().
1939      */
1940     public function test_getNumContent() {
1941         $this->resetAfterTest();
1943         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1945         // Generate h5p related data.
1946         $data = $generator->generate_h5p_data();
1948         // The 'MainLibrary' library data.
1949         $mainlibrary = $data->mainlib->data;
1951         // The 'Library1' library data.
1952         $library1 = $data->lib1->data;
1954         // Create new h5p content with MainLibrary as a main library.
1955         $generator->create_h5p_record($mainlibrary->id);
1957         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
1958         $countmainlib = $this->framework->getNumContent($mainlibrary->id);
1960         // Get the number of h5p contents that are using 'Library1' as their main library.
1961         $countlib1 = $this->framework->getNumContent($library1->id);
1963         // Make sure that 2 contents are using MainLibrary as their main library.
1964         $this->assertEquals(2, $countmainlib);
1965         // Make sure that 0 contents are using Library1 as their main library.
1966         $this->assertEquals(0, $countlib1);
1967     }
1969     /**
1970      * Test the behaviour of getNumContent() when certain contents are being skipped.
1971      */
1972     public function test_getNumContent_skip_content() {
1973         $this->resetAfterTest();
1975         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
1977         // Generate h5p related data.
1978         $data = $generator->generate_h5p_data();
1980         // The 'MainLibrary' library data.
1981         $mainlibrary = $data->mainlib->data;
1983         // Create new h5p content with MainLibrary as a main library.
1984         $h5pcontentid = $generator->create_h5p_record($mainlibrary->id);
1986         // Get the number of h5p contents that are using 'MainLibrary' as their main library.
1987         // Skip the newly created content $h5pcontentid.
1988         $countmainlib = $this->framework->getNumContent($mainlibrary->id, [$h5pcontentid]);
1990         // Make sure that 1 content is returned instead of 2 ($h5pcontentid being skipped).
1991         $this->assertEquals(1, $countmainlib);
1992     }
1994     /**
1995      * Test the behaviour of isContentSlugAvailable().
1996      */
1997     public function test_isContentSlugAvailable() {
1998         $this->resetAfterTest();
2000         $slug = 'h5p-test-slug-1';
2002         // Currently this returns always true. The slug is generated as a unique value for
2003         // each h5p content and it is not stored in the h5p content table.
2004         $isslugavailable = $this->framework->isContentSlugAvailable($slug);
2006         $this->assertTrue($isslugavailable);
2007     }
2009     /**
2010      * Test that a record is stored for cached assets.
2011      */
2012     public function test_saveCachedAssets() {
2013         global $DB;
2015         $this->resetAfterTest();
2017         $libraries = array(
2018             array(
2019                 'machineName' => 'H5P.TestLib',
2020                 'libraryId' => 405,
2021             ),
2022             array(
2023                 'FontAwesome' => 'FontAwesome',
2024                 'libraryId' => 406,
2025             ),
2026             array(
2027                 'machineName' => 'H5P.SecondLib',
2028                 'libraryId' => 407,
2029             ),
2030         );
2032         $key = 'testhashkey';
2034         $this->framework->saveCachedAssets($key, $libraries);
2036         $records = $DB->get_records('h5p_libraries_cachedassets');
2038         $this->assertCount(3, $records);
2039     }
2041     /**
2042      * Test that the correct libraries are removed from the cached assets table
2043      */
2044     public function test_deleteCachedAssets() {
2045         global $DB;
2047         $this->resetAfterTest();
2049         $libraries = array(
2050             array(
2051                 'machineName' => 'H5P.TestLib',
2052                 'libraryId' => 405,
2053             ),
2054             array(
2055                 'FontAwesome' => 'FontAwesome',
2056                 'libraryId' => 406,
2057             ),
2058             array(
2059                 'machineName' => 'H5P.SecondLib',
2060                 'libraryId' => 407,
2061             ),
2062         );
2064         $key1 = 'testhashkey';
2065         $this->framework->saveCachedAssets($key1, $libraries);
2067         $libraries = array(
2068             array(
2069                 'machineName' => 'H5P.DiffLib',
2070                 'libraryId' => 408,
2071             ),
2072             array(
2073                 'FontAwesome' => 'FontAwesome',
2074                 'libraryId' => 406,
2075             ),
2076             array(
2077                 'machineName' => 'H5P.ThirdLib',
2078                 'libraryId' => 409,
2079             ),
2080         );
2082         $key2 = 'secondhashkey';
2083         $this->framework->saveCachedAssets($key2, $libraries);
2085         $libraries = array(
2086             array(
2087                 'machineName' => 'H5P.AnotherDiffLib',
2088                 'libraryId' => 410,
2089             ),
2090             array(
2091                 'FontAwesome' => 'NotRelated',
2092                 'libraryId' => 411,
2093             ),
2094             array(
2095                 'machineName' => 'H5P.ForthLib',
2096                 'libraryId' => 412,
2097             ),
2098         );
2100         $key3 = 'threeforthewin';
2101         $this->framework->saveCachedAssets($key3, $libraries);
2103         $records = $DB->get_records('h5p_libraries_cachedassets');
2104         $this->assertCount(9, $records);
2106         // Selecting one library id will result in all related library entries also being deleted.
2107         // Going to use the FontAwesome library id. The first two hashes should be returned.
2108         $hashes = $this->framework->deleteCachedAssets(406);
2109         $this->assertCount(2, $hashes);
2110         $index = array_search($key1, $hashes);
2111         $this->assertEquals($key1, $hashes[$index]);
2112         $index = array_search($key2, $hashes);
2113         $this->assertEquals($key2, $hashes[$index]);
2114         $index = array_search($key3, $hashes);
2115         $this->assertFalse($index);
2117         // Check that the records have been removed as well.
2118         $records = $DB->get_records('h5p_libraries_cachedassets');
2119         $this->assertCount(3, $records);
2120     }
2122     /**
2123      * Test the behaviour of getLibraryContentCount().
2124      */
2125     public function test_getLibraryContentCount() {
2126         $this->resetAfterTest();
2128         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2130         // Generate h5p related data.
2131         $data = $generator->generate_h5p_data();
2133         // The 'MainLibrary' library data.
2134         $mainlibrary = $data->mainlib->data;
2136         // The 'Library2' library data.
2137         $library2 = $data->lib2->data;
2139         // Create new h5p content with Library2 as it's main library.
2140         $generator->create_h5p_record($library2->id);
2142         // Create new h5p content with MainLibrary as it's main library.
2143         $generator->create_h5p_record($mainlibrary->id);
2145         $countlibrarycontent = $this->framework->getLibraryContentCount();
2147         $expected = array(
2148             "{$mainlibrary->machinename} {$mainlibrary->majorversion}.{$mainlibrary->minorversion}" => 2,
2149             "{$library2->machinename} {$library2->majorversion}.{$library2->minorversion}" => 1,
2150         );
2152         // MainLibrary and Library1 are currently main libraries to the existing h5p contents.
2153         // Should return the number of cases where MainLibrary and Library1 are main libraries to an h5p content.
2154         $this->assertEquals($expected, $countlibrarycontent);
2155     }
2157     /**
2158      * Test the behaviour of test_libraryHasUpgrade().
2159      *
2160      * @dataProvider test_libraryHasUpgrade_provider
2161      * @param array $libraryrecords Array containing data for the library creation
2162      * @param array $testlibrary Array containing the test library data
2163      * @param bool $expected The expectation whether the library is patched or not
2164      **/
2165     public function test_libraryHasUpgrade(array $libraryrecords, array $testlibrary, bool $expected): void {
2166         $this->resetAfterTest();
2168         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2170         foreach ($libraryrecords as $library) {
2171             call_user_func_array([$generator, 'create_library_record'], $library);
2172         }
2174         $this->assertEquals($expected, $this->framework->libraryHasUpgrade($testlibrary));
2175     }
2177     /**
2178      * Data provider for test_libraryHasUpgrade().
2179      *
2180      * @return array
2181      */
2182     public function test_libraryHasUpgrade_provider(): array {
2183         return [
2184             'Lower major version; Identical lower version' => [
2185                 [
2186                     ['Library', 'Lib', 2, 2],
2187                 ],
2188                 [
2189                     'machineName' => 'Library',
2190                     'majorVersion' => 1,
2191                     'minorVersion' => 2
2192                 ],
2193                 true,
2194             ],
2195             'Major version identical; Lower minor version' => [
2196                 [
2197                     ['Library', 'Lib', 2, 2],
2198                 ],
2199                 [
2200                     'machineName' => 'Library',
2201                     'majorVersion' => 2,
2202                     'minorVersion' => 1
2203                 ],
2204                 true,
2205             ],
2206             'Major version identical; Minor version identical' => [
2207                 [
2208                     ['Library', 'Lib', 2, 2],
2209                 ],
2210                 [
2211                     'machineName' => 'Library',
2212                     'majorVersion' => 2,
2213                     'minorVersion' => 2
2214                 ],
2215                 false,
2216             ],
2217             'Major version higher; Minor version identical' => [
2218                 [
2219                     ['Library', 'Lib', 2, 2],
2220                 ],
2221                 [
2222                     'machineName' => 'Library',
2223                     'majorVersion' => 3,
2224                     'minorVersion' => 2
2225                 ],
2226                 false,
2227             ],
2228             'Major version identical; Minor version newer' => [
2229                 [
2230                     ['Library', 'Lib', 2, 2],
2231                 ],
2232                 [
2233                     'machineName' => 'Library',
2234                     'majorVersion' => 2,
2235                     'minorVersion' => 4
2236                 ],
2237                 false,
2238             ]
2239         ];
2240     }
2243     /**
2244      * Test the behaviour of get_latest_library_version().
2245      */
2246     public function test_get_latest_library_version() {
2247         global $DB;
2249         $this->resetAfterTest();
2251         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
2252         // Create a library record.
2253         $machinename = 'TestLibrary';
2254         $lib1 = $generator->create_library_record($machinename, 'Test', 1, 1, 2);
2255         $lib2 = $generator->create_library_record($machinename, 'Test', 1, 2, 1);
2257         $content = array(
2258             'params' => json_encode(['param1' => 'Test']),
2259             'library' => array(
2260                 'libraryId' => 0,
2261                 'machineName' => 'TestLibrary',
2262             ),
2263             'disable' => 8
2264         );
2266         // Get the latest id (at this point, should be lib2).
2267         $latestlib = $this->framework->get_latest_library_version($machinename);
2268         $this->assertEquals($lib2->id, $latestlib->id);
2270         // Get the latest id (at this point, should be lib3).
2271         $lib3 = $generator->create_library_record($machinename, 'Test', 2, 1, 0);
2272         $latestlib = $this->framework->get_latest_library_version($machinename);
2273         $this->assertEquals($lib3->id, $latestlib->id);
2275         // Get the latest id (at this point, should be still lib3).
2276         $lib4 = $generator->create_library_record($machinename, 'Test', 1, 1, 3);
2277         $latestlib = $this->framework->get_latest_library_version($machinename);
2278         $this->assertEquals($lib3->id, $latestlib->id);
2280         // Get the latest id (at this point, should be lib5).
2281         $lib5 = $generator->create_library_record($machinename, 'Test', 2, 1, 6);
2282         $latestlib = $this->framework->get_latest_library_version($machinename);
2283         $this->assertEquals($lib5->id, $latestlib->id);
2284     }