See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
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/>. 16 17 declare(strict_types = 1); 18 19 namespace core_h5p; 20 21 use core_h5p\local\library\autoloader; 22 23 /** 24 * Test class covering the H5P helper. 25 * 26 * @package core_h5p 27 * @category test 28 * @copyright 2019 Sara Arjona <sara@moodle.com> 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 * @covers \core_h5p\helper 31 */ 32 class helper_test extends \advanced_testcase { 33 34 /** 35 * Register the H5P autoloader 36 */ 37 protected function setUp(): void { 38 autoloader::register(); 39 } 40 41 /** 42 * Test the behaviour of get_display_options(). 43 * 44 * @dataProvider display_options_provider 45 * @param bool $frame Whether the frame should be displayed or not 46 * @param bool $export Whether the export action button should be displayed or not 47 * @param bool $embed Whether the embed action button should be displayed or not 48 * @param bool $copyright Whether the copyright action button should be displayed or not 49 * @param int $expected The expectation with the displayoptions value 50 */ 51 public function test_display_options(bool $frame, bool $export, bool $embed, bool $copyright, int $expected): void { 52 $this->setRunTestInSeparateProcess(true); 53 $this->resetAfterTest(); 54 55 $factory = new \core_h5p\factory(); 56 $core = $factory->get_core(); 57 $config = (object)[ 58 'frame' => $frame, 59 'export' => $export, 60 'embed' => $embed, 61 'copyright' => $copyright, 62 ]; 63 64 // Test getting display options. 65 $displayoptions = helper::get_display_options($core, $config); 66 $this->assertEquals($expected, $displayoptions); 67 68 // Test decoding display options. 69 $decoded = helper::decode_display_options($core, $expected); 70 $this->assertEquals($decoded->export, $config->export); 71 $this->assertEquals($decoded->embed, $config->embed); 72 $this->assertEquals($decoded->copyright, $config->copyright); 73 } 74 75 /** 76 * Data provider for test_get_display_options(). 77 * 78 * @return array 79 */ 80 public function display_options_provider(): array { 81 return [ 82 'All display options disabled' => [ 83 false, 84 false, 85 false, 86 false, 87 15, 88 ], 89 'All display options enabled' => [ 90 true, 91 true, 92 true, 93 true, 94 0, 95 ], 96 'Frame disabled and the rest enabled' => [ 97 false, 98 true, 99 true, 100 true, 101 0, 102 ], 103 'Only export enabled' => [ 104 false, 105 true, 106 false, 107 false, 108 12, 109 ], 110 'Only embed enabled' => [ 111 false, 112 false, 113 true, 114 false, 115 10, 116 ], 117 'Only copyright enabled' => [ 118 false, 119 false, 120 false, 121 true, 122 6, 123 ], 124 ]; 125 } 126 127 /** 128 * Test the behaviour of save_h5p() when there are some missing libraries in the system. 129 * @runInSeparateProcess 130 */ 131 public function test_save_h5p_missing_libraries(): void { 132 $this->resetAfterTest(); 133 $factory = new \core_h5p\factory(); 134 135 // Create a user. 136 $user = $this->getDataGenerator()->create_user(); 137 $this->setUser($user); 138 139 // This is a valid .H5P file. 140 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 141 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 142 $factory->get_framework()->set_file($file); 143 144 $config = (object)[ 145 'frame' => 1, 146 'export' => 1, 147 'embed' => 0, 148 'copyright' => 0, 149 ]; 150 151 // There are some missing libraries in the system, so an error should be returned. 152 $h5pid = helper::save_h5p($factory, $file, $config); 153 $this->assertFalse($h5pid); 154 $errors = $factory->get_framework()->getMessages('error'); 155 $this->assertCount(1, $errors); 156 $error = reset($errors); 157 $this->assertEquals('missing-required-library', $error->code); 158 $this->assertEquals('Missing required library H5P.GreetingCard 1.0', $error->message); 159 } 160 161 /** 162 * Test the behaviour of save_h5p() when the libraries exist in the system. 163 * @runInSeparateProcess 164 */ 165 public function test_save_h5p_existing_libraries(): void { 166 global $DB; 167 168 $this->resetAfterTest(); 169 $factory = new \core_h5p\factory(); 170 171 // Create a user. 172 $user = $this->getDataGenerator()->create_user(); 173 $this->setUser($user); 174 175 // This is a valid .H5P file. 176 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 177 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 178 $factory->get_framework()->set_file($file); 179 180 $config = (object)[ 181 'frame' => 1, 182 'export' => 1, 183 'embed' => 0, 184 'copyright' => 0, 185 ]; 186 // The required libraries exist in the system before saving the .h5p file. 187 $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 188 $lib = $generator->create_library_record('H5P.GreetingCard', 'GreetingCard', 1, 0); 189 $h5pid = helper::save_h5p($factory, $file, $config); 190 $this->assertNotEmpty($h5pid); 191 192 // No errors are raised. 193 $errors = $factory->get_framework()->getMessages('error'); 194 $this->assertCount(0, $errors); 195 196 // And the content in the .h5p file has been saved as expected. 197 $h5p = $DB->get_record('h5p', ['id' => $h5pid]); 198 $this->assertEquals($lib->id, $h5p->mainlibraryid); 199 $this->assertEquals(helper::get_display_options($factory->get_core(), $config), $h5p->displayoptions); 200 $this->assertStringContainsString('Hello world!', $h5p->jsoncontent); 201 } 202 203 204 /** 205 * Test the behaviour of save_h5p() when the H5P file contains metadata. 206 * 207 * @runInSeparateProcess 208 * @covers ::save_h5p 209 */ 210 public function test_save_h5p_metadata(): void { 211 global $DB; 212 213 $this->resetAfterTest(); 214 $factory = new \core_h5p\factory(); 215 216 // Create a user. 217 $user = $this->getDataGenerator()->create_user(); 218 $this->setUser($user); 219 220 // This is a valid .H5P file. 221 $path = __DIR__ . '/fixtures/guess-the-answer.h5p'; 222 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 223 $factory->get_framework()->set_file($file); 224 225 $config = (object)[ 226 'frame' => 1, 227 'export' => 1, 228 'embed' => 0, 229 'copyright' => 1, 230 ]; 231 // The required libraries exist in the system before saving the .h5p file. 232 $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 233 $lib = $generator->create_library_record('H5P.GuessTheAnswer', 'Guess the Answer', 1, 5); 234 $generator->create_library_record('H5P.Image', 'Image', 1, 1); 235 $generator->create_library_record('FontAwesome', 'Font Awesome', 4, 5); 236 $h5pid = helper::save_h5p($factory, $file, $config); 237 $this->assertNotEmpty($h5pid); 238 239 // No errors are raised. 240 $errors = $factory->get_framework()->getMessages('error'); 241 $this->assertCount(0, $errors); 242 243 // And the content in the .h5p file has been saved as expected. 244 $h5p = $DB->get_record('h5p', ['id' => $h5pid]); 245 $this->assertEquals($lib->id, $h5p->mainlibraryid); 246 $this->assertEquals(helper::get_display_options($factory->get_core(), $config), $h5p->displayoptions); 247 $this->assertStringContainsString('Which fruit is this?', $h5p->jsoncontent); 248 // Metadata has been also saved. 249 $this->assertStringContainsString('This is licence extras information added for testing purposes.', $h5p->jsoncontent); 250 $this->assertStringContainsString('H5P Author', $h5p->jsoncontent); 251 $this->assertStringContainsString('Add metadata information', $h5p->jsoncontent); 252 } 253 254 /** 255 * Test the behaviour of save_h5p() when the .h5p file is invalid. 256 * @runInSeparateProcess 257 */ 258 public function test_save_h5p_invalid_file(): void { 259 $this->resetAfterTest(); 260 $factory = new \core_h5p\factory(); 261 262 // Create a user. 263 $user = $this->getDataGenerator()->create_user(); 264 $this->setUser($user); 265 266 // Prepare an invalid .H5P file. 267 $path = __DIR__ . '/fixtures/h5ptest.zip'; 268 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 269 $factory->get_framework()->set_file($file); 270 $config = (object)[ 271 'frame' => 1, 272 'export' => 1, 273 'embed' => 0, 274 'copyright' => 0, 275 ]; 276 277 // When saving an invalid .h5p file, an error should be raised. 278 $h5pid = helper::save_h5p($factory, $file, $config); 279 $this->assertFalse($h5pid); 280 $errors = $factory->get_framework()->getMessages('error'); 281 $this->assertCount(2, $errors); 282 283 $expectederrorcodes = ['invalid-content-folder', 'invalid-h5p-json-file']; 284 foreach ($errors as $error) { 285 $this->assertContains($error->code, $expectederrorcodes); 286 } 287 } 288 289 /** 290 * Test the behaviour of can_deploy_package(). 291 */ 292 public function test_can_deploy_package(): void { 293 $this->resetAfterTest(); 294 $factory = new \core_h5p\factory(); 295 296 // Create a user. 297 $user = $this->getDataGenerator()->create_user(); 298 $admin = get_admin(); 299 300 // Prepare a valid .H5P file. 301 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 302 303 // Files created by users can't be deployed. 304 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 305 $factory->get_framework()->set_file($file); 306 $candeploy = helper::can_deploy_package($file); 307 $this->assertFalse($candeploy); 308 309 // Files created by admins can be deployed, even when the current user is not the admin. 310 $this->setUser($user); 311 $file = helper::create_fake_stored_file_from_path($path, (int)$admin->id); 312 $factory->get_framework()->set_file($file); 313 $candeploy = helper::can_deploy_package($file); 314 $this->assertTrue($candeploy); 315 } 316 317 /** 318 * Test the behaviour of can_update_library(). 319 */ 320 public function test_can_update_library(): void { 321 $this->resetAfterTest(); 322 $factory = new \core_h5p\factory(); 323 324 // Create a user. 325 $user = $this->getDataGenerator()->create_user(); 326 $admin = get_admin(); 327 328 // Prepare a valid .H5P file. 329 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 330 331 // Libraries can't be updated when the file has been created by users. 332 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 333 $factory->get_framework()->set_file($file); 334 $candeploy = helper::can_update_library($file); 335 $this->assertFalse($candeploy); 336 337 // Libraries can be updated when the file has been created by admin, even when the current user is not the admin. 338 $this->setUser($user); 339 $file = helper::create_fake_stored_file_from_path($path, (int)$admin->id); 340 $factory->get_framework()->set_file($file); 341 $candeploy = helper::can_update_library($file); 342 $this->assertTrue($candeploy); 343 } 344 345 /** 346 * Test the behaviour of get_messages(). 347 */ 348 public function test_get_messages(): void { 349 $this->resetAfterTest(); 350 351 $factory = new \core_h5p\factory(); 352 $messages = new \stdClass(); 353 354 helper::get_messages($messages, $factory); 355 $this->assertTrue(empty($messages->error)); 356 $this->assertTrue(empty($messages->info)); 357 358 // Add an some messages manually and check they are still there. 359 $messages->error = []; 360 $messages->error['error1'] = 'Testing ERROR message'; 361 $messages->info = []; 362 $messages->info['info1'] = 'Testing INFO message'; 363 $messages->info['info2'] = 'Testing INFO message'; 364 helper::get_messages($messages, $factory); 365 $this->assertCount(1, $messages->error); 366 $this->assertCount(2, $messages->info); 367 368 // When saving an invalid .h5p file, 6 errors should be raised. 369 $path = __DIR__ . '/fixtures/h5ptest.zip'; 370 $file = helper::create_fake_stored_file_from_path($path); 371 $factory->get_framework()->set_file($file); 372 $config = (object)[ 373 'frame' => 1, 374 'export' => 1, 375 'embed' => 0, 376 'copyright' => 0, 377 ]; 378 $h5pid = helper::save_h5p($factory, $file, $config); 379 $this->assertFalse($h5pid); 380 helper::get_messages($messages, $factory); 381 $this->assertCount(7, $messages->error); 382 $this->assertCount(2, $messages->info); 383 } 384 385 /** 386 * Test the behaviour of get_export_info(). 387 */ 388 public function test_get_export_info(): void { 389 $this->resetAfterTest(); 390 391 $filename = 'guess-the-answer.h5p'; 392 $syscontext = \context_system::instance(); 393 394 $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 395 $deployedfile = $generator->create_export_file($filename, 396 $syscontext->id, 397 file_storage::COMPONENT, 398 file_storage::EXPORT_FILEAREA); 399 400 // Test scenario 1: Get export information from correct filename. 401 $helperfile = helper::get_export_info($deployedfile['filename']); 402 $this->assertEquals($deployedfile['filename'], $helperfile['filename']); 403 $this->assertEquals($deployedfile['filepath'], $helperfile['filepath']); 404 $this->assertEquals($deployedfile['filesize'], $helperfile['filesize']); 405 $this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']); 406 $this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']); 407 408 // Test scenario 2: Get export information from correct filename and url. 409 $url = \moodle_url::make_pluginfile_url( 410 $syscontext->id, 411 file_storage::COMPONENT, 412 'unittest', 413 0, 414 '/', 415 $deployedfile['filename'], 416 false, 417 true 418 ); 419 $helperfile = helper::get_export_info($deployedfile['filename'], $url); 420 $this->assertEquals($url, $helperfile['fileurl']); 421 422 // Test scenario 3: Get export information from correct filename and factory. 423 $factory = new \core_h5p\factory(); 424 $helperfile = helper::get_export_info($deployedfile['filename'], null, $factory); 425 $this->assertEquals($deployedfile['filename'], $helperfile['filename']); 426 $this->assertEquals($deployedfile['filepath'], $helperfile['filepath']); 427 $this->assertEquals($deployedfile['filesize'], $helperfile['filesize']); 428 $this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']); 429 $this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']); 430 431 // Test scenario 4: Get export information from wrong filename. 432 $helperfile = helper::get_export_info('nofileexist.h5p', $url); 433 $this->assertNull($helperfile); 434 } 435 436 /** 437 * Test the parse_js_array function with a range of content. 438 * 439 * @dataProvider parse_js_array_provider 440 * @param string $content 441 * @param array $expected 442 */ 443 public function test_parse_js_array(string $content, array $expected): void { 444 $this->assertEquals($expected, helper::parse_js_array($content)); 445 } 446 447 /** 448 * Data provider for test_parse_js_array(). 449 * 450 * @return array 451 */ 452 public function parse_js_array_provider(): array { 453 $lines = [ 454 "{", 455 " missingTranslation: '[Missing translation :key]',", 456 " loading: 'Loading, please wait...',", 457 " selectLibrary: 'Select the library you wish to use for your content.',", 458 "}", 459 ]; 460 $expected = [ 461 'missingTranslation' => '[Missing translation :key]', 462 'loading' => 'Loading, please wait...', 463 'selectLibrary' => 'Select the library you wish to use for your content.', 464 ]; 465 return [ 466 'Strings with \n' => [ 467 implode("\n", $lines), 468 $expected, 469 ], 470 'Strings with \r\n' => [ 471 implode("\r\n", $lines), 472 $expected, 473 ], 474 'Strings with \r' => [ 475 implode("\r", $lines), 476 $expected, 477 ], 478 ]; 479 } 480 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body