Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]
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-main-library', $error->code); 158 $this->assertEquals('Missing main 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 * Test the behaviour of save_h5p() when the H5P file contains metadata. 205 * 206 * @runInSeparateProcess 207 * @covers ::save_h5p 208 */ 209 public function test_save_h5p_metadata(): void { 210 global $DB; 211 212 $this->resetAfterTest(); 213 $factory = new \core_h5p\factory(); 214 215 // Create a user. 216 $user = $this->getDataGenerator()->create_user(); 217 $this->setUser($user); 218 219 // This is a valid .H5P file. 220 $path = __DIR__ . '/fixtures/guess-the-answer.h5p'; 221 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 222 $factory->get_framework()->set_file($file); 223 224 $config = (object)[ 225 'frame' => 1, 226 'export' => 1, 227 'embed' => 0, 228 'copyright' => 1, 229 ]; 230 // The required libraries exist in the system before saving the .h5p file. 231 $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 232 $lib = $generator->create_library_record('H5P.GuessTheAnswer', 'Guess the Answer', 1, 5); 233 $generator->create_library_record('H5P.Image', 'Image', 1, 1); 234 $generator->create_library_record('FontAwesome', 'Font Awesome', 4, 5); 235 $h5pid = helper::save_h5p($factory, $file, $config); 236 $this->assertNotEmpty($h5pid); 237 238 // No errors are raised. 239 $errors = $factory->get_framework()->getMessages('error'); 240 $this->assertCount(0, $errors); 241 242 // And the content in the .h5p file has been saved as expected. 243 $h5p = $DB->get_record('h5p', ['id' => $h5pid]); 244 $this->assertEquals($lib->id, $h5p->mainlibraryid); 245 $this->assertEquals(helper::get_display_options($factory->get_core(), $config), $h5p->displayoptions); 246 $this->assertStringContainsString('Which fruit is this?', $h5p->jsoncontent); 247 // Metadata has been also saved. 248 $this->assertStringContainsString('This is licence extras information added for testing purposes.', $h5p->jsoncontent); 249 $this->assertStringContainsString('H5P Author', $h5p->jsoncontent); 250 $this->assertStringContainsString('Add metadata information', $h5p->jsoncontent); 251 } 252 253 /** 254 * Test the behaviour of save_h5p() when the .h5p file is invalid. 255 * @runInSeparateProcess 256 */ 257 public function test_save_h5p_invalid_file(): void { 258 $this->resetAfterTest(); 259 $factory = new \core_h5p\factory(); 260 261 // Create a user. 262 $user = $this->getDataGenerator()->create_user(); 263 $this->setUser($user); 264 265 // Prepare an invalid .H5P file. 266 $path = __DIR__ . '/fixtures/h5ptest.zip'; 267 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 268 $factory->get_framework()->set_file($file); 269 $config = (object)[ 270 'frame' => 1, 271 'export' => 1, 272 'embed' => 0, 273 'copyright' => 0, 274 ]; 275 276 // When saving an invalid .h5p file, an error should be raised. 277 $h5pid = helper::save_h5p($factory, $file, $config); 278 $this->assertFalse($h5pid); 279 $errors = $factory->get_framework()->getMessages('error'); 280 $this->assertCount(2, $errors); 281 282 $expectederrorcodes = ['invalid-content-folder', 'invalid-h5p-json-file']; 283 foreach ($errors as $error) { 284 $this->assertContains($error->code, $expectederrorcodes); 285 } 286 } 287 288 /** 289 * Test the behaviour of can_deploy_package(). 290 */ 291 public function test_can_deploy_package(): void { 292 $this->resetAfterTest(); 293 $factory = new \core_h5p\factory(); 294 295 // Create a user. 296 $user = $this->getDataGenerator()->create_user(); 297 $admin = get_admin(); 298 299 // Prepare a valid .H5P file. 300 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 301 302 // Files created by users can't be deployed. 303 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 304 $factory->get_framework()->set_file($file); 305 $candeploy = helper::can_deploy_package($file); 306 $this->assertFalse($candeploy); 307 308 // Files created by admins can be deployed, even when the current user is not the admin. 309 $this->setUser($user); 310 $file = helper::create_fake_stored_file_from_path($path, (int)$admin->id); 311 $factory->get_framework()->set_file($file); 312 $candeploy = helper::can_deploy_package($file); 313 $this->assertTrue($candeploy); 314 } 315 316 /** 317 * Test the behaviour of can_update_library(). 318 */ 319 public function test_can_update_library(): void { 320 $this->resetAfterTest(); 321 $factory = new \core_h5p\factory(); 322 323 // Create a user. 324 $user = $this->getDataGenerator()->create_user(); 325 $admin = get_admin(); 326 327 // Prepare a valid .H5P file. 328 $path = __DIR__ . '/fixtures/greeting-card.h5p'; 329 330 // Libraries can't be updated when the file has been created by users. 331 $file = helper::create_fake_stored_file_from_path($path, (int)$user->id); 332 $factory->get_framework()->set_file($file); 333 $candeploy = helper::can_update_library($file); 334 $this->assertFalse($candeploy); 335 336 // Libraries can be updated when the file has been created by admin, even when the current user is not the admin. 337 $this->setUser($user); 338 $file = helper::create_fake_stored_file_from_path($path, (int)$admin->id); 339 $factory->get_framework()->set_file($file); 340 $candeploy = helper::can_update_library($file); 341 $this->assertTrue($candeploy); 342 } 343 344 /** 345 * Test the behaviour of get_messages(). 346 */ 347 public function test_get_messages(): void { 348 $this->resetAfterTest(); 349 350 $factory = new \core_h5p\factory(); 351 $messages = new \stdClass(); 352 353 helper::get_messages($messages, $factory); 354 $this->assertTrue(empty($messages->error)); 355 $this->assertTrue(empty($messages->info)); 356 357 // Add an some messages manually and check they are still there. 358 $messages->error = []; 359 $messages->error['error1'] = 'Testing ERROR message'; 360 $messages->info = []; 361 $messages->info['info1'] = 'Testing INFO message'; 362 $messages->info['info2'] = 'Testing INFO message'; 363 helper::get_messages($messages, $factory); 364 $this->assertCount(1, $messages->error); 365 $this->assertCount(2, $messages->info); 366 367 // When saving an invalid .h5p file, 6 errors should be raised. 368 $path = __DIR__ . '/fixtures/h5ptest.zip'; 369 $file = helper::create_fake_stored_file_from_path($path); 370 $factory->get_framework()->set_file($file); 371 $config = (object)[ 372 'frame' => 1, 373 'export' => 1, 374 'embed' => 0, 375 'copyright' => 0, 376 ]; 377 $h5pid = helper::save_h5p($factory, $file, $config); 378 $this->assertFalse($h5pid); 379 helper::get_messages($messages, $factory); 380 $this->assertCount(7, $messages->error); 381 $this->assertCount(2, $messages->info); 382 } 383 384 /** 385 * Test the behaviour of get_export_info(). 386 */ 387 public function test_get_export_info(): void { 388 $this->resetAfterTest(); 389 390 $filename = 'guess-the-answer.h5p'; 391 $syscontext = \context_system::instance(); 392 393 $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p'); 394 $deployedfile = $generator->create_export_file($filename, 395 $syscontext->id, 396 file_storage::COMPONENT, 397 file_storage::EXPORT_FILEAREA); 398 399 // Test scenario 1: Get export information from correct filename. 400 $helperfile = helper::get_export_info($deployedfile['filename']); 401 $this->assertEquals($deployedfile['filename'], $helperfile['filename']); 402 $this->assertEquals($deployedfile['filepath'], $helperfile['filepath']); 403 $this->assertEquals($deployedfile['filesize'], $helperfile['filesize']); 404 $this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']); 405 $this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']); 406 407 // Test scenario 2: Get export information from correct filename and url. 408 $url = \moodle_url::make_pluginfile_url( 409 $syscontext->id, 410 file_storage::COMPONENT, 411 'unittest', 412 0, 413 '/', 414 $deployedfile['filename'], 415 false, 416 true 417 ); 418 $helperfile = helper::get_export_info($deployedfile['filename'], $url); 419 $this->assertEquals($url, $helperfile['fileurl']); 420 421 // Test scenario 3: Get export information from correct filename and factory. 422 $factory = new \core_h5p\factory(); 423 $helperfile = helper::get_export_info($deployedfile['filename'], null, $factory); 424 $this->assertEquals($deployedfile['filename'], $helperfile['filename']); 425 $this->assertEquals($deployedfile['filepath'], $helperfile['filepath']); 426 $this->assertEquals($deployedfile['filesize'], $helperfile['filesize']); 427 $this->assertEquals($deployedfile['timemodified'], $helperfile['timemodified']); 428 $this->assertEquals($deployedfile['fileurl'], $helperfile['fileurl']); 429 430 // Test scenario 4: Get export information from wrong filename. 431 $helperfile = helper::get_export_info('nofileexist.h5p', $url); 432 $this->assertNull($helperfile); 433 } 434 435 /** 436 * Test the parse_js_array function with a range of content. 437 * 438 * @dataProvider parse_js_array_provider 439 * @param string $content 440 * @param array $expected 441 */ 442 public function test_parse_js_array(string $content, array $expected): void { 443 $this->assertEquals($expected, helper::parse_js_array($content)); 444 } 445 446 /** 447 * Data provider for test_parse_js_array(). 448 * 449 * @return array 450 */ 451 public function parse_js_array_provider(): array { 452 $lines = [ 453 "{", 454 " missingTranslation: '[Missing translation :key]',", 455 " loading: 'Loading, please wait...',", 456 " selectLibrary: 'Select the library you wish to use for your content.',", 457 "}", 458 ]; 459 $expected = [ 460 'missingTranslation' => '[Missing translation :key]', 461 'loading' => 'Loading, please wait...', 462 'selectLibrary' => 'Select the library you wish to use for your content.', 463 ]; 464 return [ 465 'Strings with \n' => [ 466 implode("\n", $lines), 467 $expected, 468 ], 469 'Strings with \r\n' => [ 470 implode("\r\n", $lines), 471 $expected, 472 ], 473 'Strings with \r' => [ 474 implode("\r", $lines), 475 $expected, 476 ], 477 ]; 478 } 479 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body