Differences Between: [Versions 400 and 403] [Versions 401 and 403] [Versions 402 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 /** 18 * Course related unit tests 19 * 20 * @package core_course 21 * @copyright 2014 Marina Glancy 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 * @coversDefaultClass \core_courseformat\base 24 */ 25 class base_test extends advanced_testcase { 26 27 /** 28 * Setup to ensure that fixtures are loaded. 29 */ 30 public static function setupBeforeClass(): void { 31 global $CFG; 32 require_once($CFG->dirroot . '/course/lib.php'); 33 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php'); 34 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_state.php'); 35 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_invalidoutput.php'); 36 } 37 38 /** 39 * Tests the save and load functionality. 40 * 41 * @author Jason den Dulk 42 * @covers \core_courseformat 43 */ 44 public function test_courseformat_saveandload() { 45 $this->resetAfterTest(); 46 47 $courseformatoptiondata = (object) [ 48 "hideoddsections" => 1, 49 'summary_editor' => [ 50 'text' => '<p>Somewhere over the rainbow</p><p>The <b>quick</b> brown fox jumpos over the lazy dog.</p>', 51 'format' => 1 52 ] 53 ]; 54 $generator = $this->getDataGenerator(); 55 $course1 = $generator->create_course(array('format' => 'theunittest')); 56 $this->assertEquals('theunittest', $course1->format); 57 course_create_sections_if_missing($course1, array(0, 1)); 58 59 $courseformat = course_get_format($course1); 60 $courseformat->update_course_format_options($courseformatoptiondata); 61 62 $savedcourseformatoptiondata = $courseformat->get_format_options(); 63 64 $this->assertEqualsCanonicalizing($courseformatoptiondata, (object) $savedcourseformatoptiondata); 65 } 66 67 public function test_available_hook() { 68 global $DB; 69 $this->resetAfterTest(); 70 71 // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'theunittest'. 72 $generator = $this->getDataGenerator(); 73 $course1 = $generator->create_course(array('format' => 'theunittest')); 74 $this->assertEquals('theunittest', $course1->format); 75 course_create_sections_if_missing($course1, array(0, 1)); 76 $assign0 = $generator->create_module('assign', array('course' => $course1, 'section' => 0)); 77 $assign1 = $generator->create_module('assign', array('course' => $course1, 'section' => 1)); 78 $assign2 = $generator->create_module('assign', array('course' => $course1, 'section' => 0, 'visible' => 0)); 79 80 // Create a courseoverview role based on the student role. 81 $roleattr = array('name' => 'courseoverview', 'shortname' => 'courseoverview', 'archetype' => 'student'); 82 $generator->create_role($roleattr); 83 84 // Create user student, editingteacher, teacher and courseoverview. 85 $student = $generator->create_user(); 86 $teacher = $generator->create_user(); 87 $editingteacher = $generator->create_user(); 88 $courseoverviewuser = $generator->create_user(); 89 90 // Enrol users into their roles. 91 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); 92 $generator->enrol_user($student->id, $course1->id, $roleids['student']); 93 $generator->enrol_user($teacher->id, $course1->id, $roleids['teacher']); 94 $generator->enrol_user($editingteacher->id, $course1->id, $roleids['editingteacher']); 95 $generator->enrol_user($courseoverviewuser->id, $course1->id, $roleids['courseoverview']); 96 97 // Remove the ignoreavailabilityrestrictions from the teacher role. 98 role_change_permission($roleids['teacher'], context_system::instance(0), 99 'moodle/course:ignoreavailabilityrestrictions', CAP_PREVENT); 100 101 // Allow the courseoverview role to ingore available restriction. 102 role_change_permission($roleids['courseoverview'], context_system::instance(0), 103 'moodle/course:ignoreavailabilityrestrictions', CAP_ALLOW); 104 105 // Make sure that initially both sections and both modules are available and visible for a student. 106 $modinfostudent = get_fast_modinfo($course1, $student->id); 107 $this->assertTrue($modinfostudent->get_section_info(1)->available); 108 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 109 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 110 $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->available); 111 $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->uservisible); 112 $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible); 113 114 // Set 'hideoddsections' for the course to 1. 115 // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher. 116 $data = (object)array('id' => $course1->id, 'hideoddsections' => 1); 117 course_get_format($course1)->update_course_format_options($data); 118 $modinfostudent = get_fast_modinfo($course1, $student->id); 119 $this->assertFalse($modinfostudent->get_section_info(1)->available); 120 $this->assertEmpty($modinfostudent->get_section_info(1)->availableinfo); 121 $this->assertFalse($modinfostudent->get_section_info(1)->uservisible); 122 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 123 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 124 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available); 125 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible); 126 $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible); 127 128 $modinfoteacher = get_fast_modinfo($course1, $teacher->id); 129 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 130 $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo); 131 $this->assertFalse($modinfoteacher->get_section_info(1)->uservisible); 132 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 133 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 134 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 135 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->uservisible); 136 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->available); 137 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible); 138 139 $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id); 140 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 141 $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo); 142 $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible); 143 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 144 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 145 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 146 $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible); 147 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible); 148 149 $modinfocourseoverview = get_fast_modinfo($course1, $courseoverviewuser->id); 150 $this->assertFalse($modinfocourseoverview->get_section_info(1)->available); 151 $this->assertEmpty($modinfocourseoverview->get_section_info(1)->availableinfo); 152 $this->assertTrue($modinfocourseoverview->get_section_info(1)->uservisible); 153 $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->available); 154 $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->uservisible); 155 $this->assertFalse($modinfocourseoverview->get_cm($assign1->cmid)->available); 156 $this->assertTrue($modinfocourseoverview->get_cm($assign1->cmid)->uservisible); 157 $this->assertFalse($modinfocourseoverview->get_cm($assign2->cmid)->uservisible); 158 159 // Set 'hideoddsections' for the course to 2. 160 // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher. 161 // Property availableinfo will be not empty. 162 $data = (object)array('id' => $course1->id, 'hideoddsections' => 2); 163 course_get_format($course1)->update_course_format_options($data); 164 $modinfostudent = get_fast_modinfo($course1, $student->id); 165 $this->assertFalse($modinfostudent->get_section_info(1)->available); 166 $this->assertNotEmpty($modinfostudent->get_section_info(1)->availableinfo); 167 $this->assertFalse($modinfostudent->get_section_info(1)->uservisible); 168 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 169 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 170 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available); 171 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible); 172 173 $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id); 174 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 175 $this->assertNotEmpty($modinfoteacher->get_section_info(1)->availableinfo); 176 $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible); 177 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 178 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 179 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 180 $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible); 181 } 182 183 /** 184 * Test for supports_news() with a course format plugin that doesn't define 'news_items' in default blocks. 185 */ 186 public function test_supports_news() { 187 $this->resetAfterTest(); 188 $format = course_get_format((object)['format' => 'testformat']); 189 $this->assertFalse($format->supports_news()); 190 } 191 192 /** 193 * Test for supports_news() for old course format plugins that defines 'news_items' in default blocks. 194 */ 195 public function test_supports_news_legacy() { 196 $this->resetAfterTest(); 197 $format = course_get_format((object)['format' => 'testlegacy']); 198 $this->assertTrue($format->supports_news()); 199 } 200 201 /** 202 * Test for get_view_url() to ensure that the url is only given for the correct cases 203 */ 204 public function test_get_view_url() { 205 global $CFG; 206 $this->resetAfterTest(); 207 208 $linkcoursesections = $CFG->linkcoursesections; 209 210 // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'testformat'. 211 // This will allow us to test the default implementation of get_view_url. 212 $generator = $this->getDataGenerator(); 213 $course1 = $generator->create_course(array('format' => 'testformat')); 214 course_create_sections_if_missing($course1, array(0, 1)); 215 216 $data = (object)['id' => $course1->id]; 217 $format = course_get_format($course1); 218 $format->update_course_format_options($data); 219 220 // In page. 221 $CFG->linkcoursesections = 0; 222 $this->assertNotEmpty($format->get_view_url(null)); 223 $this->assertNotEmpty($format->get_view_url(0)); 224 $this->assertNotEmpty($format->get_view_url(1)); 225 $CFG->linkcoursesections = 1; 226 $this->assertNotEmpty($format->get_view_url(null)); 227 $this->assertNotEmpty($format->get_view_url(0)); 228 $this->assertNotEmpty($format->get_view_url(1)); 229 230 // Navigation. 231 $CFG->linkcoursesections = 0; 232 $this->assertNull($format->get_view_url(1, ['navigation' => 1])); 233 $this->assertNull($format->get_view_url(0, ['navigation' => 1])); 234 $CFG->linkcoursesections = 1; 235 $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); 236 $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); 237 238 // Expand section. 239 // The current course format $format uses the format 'testformat' which does not use sections. 240 // Thus, the 'expanded' parameter does not do anything. 241 $viewurl = $format->get_view_url(1); 242 $this->assertNull($viewurl->get_param('expandsection')); 243 $viewurl = $format->get_view_url(1, ['expanded' => 1]); 244 $this->assertNull($viewurl->get_param('expandsection')); 245 $viewurl = $format->get_view_url(1, ['expanded' => 0]); 246 $this->assertNull($viewurl->get_param('expandsection')); 247 // We now use a course format which uses sections. 248 $course2 = $generator->create_course(['format' => 'testformatsections']); 249 course_create_sections_if_missing($course1, [0, 2]); 250 $formatwithsections = course_get_format($course2); 251 $viewurl = $formatwithsections->get_view_url(2); 252 $this->assertEquals(2, $viewurl->get_param('expandsection')); 253 $viewurl = $formatwithsections->get_view_url(2, ['expanded' => 1]); 254 $this->assertEquals(2, $viewurl->get_param('expandsection')); 255 $viewurl = $formatwithsections->get_view_url(2, ['expanded' => 0]); 256 $this->assertNull($viewurl->get_param('expandsection')); 257 } 258 259 /** 260 * Test for get_output_classname method. 261 * 262 * @dataProvider get_output_classname_provider 263 * @param string $find the class to find 264 * @param string $result the expected result classname 265 * @param bool $exception if the method will raise an exception 266 */ 267 public function test_get_output_classname($find, $result, $exception) { 268 $this->resetAfterTest(); 269 270 $course = $this->getDataGenerator()->create_course(['format' => 'theunittest']); 271 $courseformat = course_get_format($course); 272 273 if ($exception) { 274 $this->expectException(coding_exception::class); 275 } 276 277 $courseclass = $courseformat->get_output_classname($find); 278 $this->assertEquals($result, $courseclass); 279 } 280 281 /** 282 * Data provider for test_get_output_classname. 283 * 284 * @return array the testing scenarios 285 */ 286 public function get_output_classname_provider(): array { 287 return [ 288 'overridden class' => [ 289 'find' => 'state\\course', 290 'result' => 'format_theunittest\\output\\courseformat\\state\\course', 291 'exception' => false, 292 ], 293 'original class' => [ 294 'find' => 'state\\section', 295 'result' => 'core_courseformat\\output\\local\\state\\section', 296 'exception' => false, 297 ], 298 'invalid overridden class' => [ 299 'find' => 'state\\invalidoutput', 300 'result' => '', 301 'exception' => true, 302 ], 303 ]; 304 } 305 306 /** 307 * Test for the default delete format data behaviour. 308 * 309 * @covers ::get_sections_preferences 310 */ 311 public function test_get_sections_preferences() { 312 $this->resetAfterTest(); 313 $generator = $this->getDataGenerator(); 314 $course = $generator->create_course(); 315 $user = $generator->create_and_enrol($course, 'student'); 316 317 // Create fake preferences generated by the frontend js module. 318 $data = (object)[ 319 'pref1' => [1,2], 320 'pref2' => [1], 321 ]; 322 set_user_preference('coursesectionspreferences_' . $course->id, json_encode($data), $user->id); 323 324 $format = course_get_format($course); 325 326 // Load data from user 1. 327 $this->setUser($user); 328 $preferences = $format->get_sections_preferences(); 329 330 $this->assertEquals( 331 (object)['pref1' => true, 'pref2' => true], 332 $preferences[1] 333 ); 334 $this->assertEquals( 335 (object)['pref1' => true], 336 $preferences[2] 337 ); 338 } 339 340 /** 341 * Test for the default delete format data behaviour. 342 * 343 * @covers ::set_sections_preference 344 */ 345 public function test_set_sections_preference() { 346 $this->resetAfterTest(); 347 $generator = $this->getDataGenerator(); 348 $course = $generator->create_course(); 349 $user = $generator->create_and_enrol($course, 'student'); 350 351 $format = course_get_format($course); 352 $this->setUser($user); 353 354 // Load data from user 1. 355 $format->set_sections_preference('pref1', [1, 2]); 356 $format->set_sections_preference('pref2', [1]); 357 $format->set_sections_preference('pref3', []); 358 359 $preferences = $format->get_sections_preferences(); 360 $this->assertEquals( 361 (object)['pref1' => true, 'pref2' => true], 362 $preferences[1] 363 ); 364 $this->assertEquals( 365 (object)['pref1' => true], 366 $preferences[2] 367 ); 368 } 369 370 /** 371 * Test that retrieving last section number for a course 372 * 373 * @covers ::get_last_section_number 374 */ 375 public function test_get_last_section_number(): void { 376 global $DB; 377 378 $this->resetAfterTest(); 379 380 // Course with two additional sections. 381 $courseone = $this->getDataGenerator()->create_course(['numsections' => 2]); 382 $this->assertEquals(2, course_get_format($courseone)->get_last_section_number()); 383 384 // Course without additional sections, section zero is the "default" section that always exists. 385 $coursetwo = $this->getDataGenerator()->create_course(['numsections' => 0]); 386 $this->assertEquals(0, course_get_format($coursetwo)->get_last_section_number()); 387 388 // Course without additional sections, manually remove section zero, as "course_delete_section" prevents that. This 389 // simulates course data integrity issues that previously triggered errors. 390 $coursethree = $this->getDataGenerator()->create_course(['numsections' => 0]); 391 $DB->delete_records('course_sections', ['course' => $coursethree->id, 'section' => 0]); 392 393 $this->assertEquals(-1, course_get_format($coursethree)->get_last_section_number()); 394 } 395 396 /** 397 * Test for the default delete format data behaviour. 398 * 399 * @covers ::delete_format_data 400 * @dataProvider delete_format_data_provider 401 * @param bool $usehook if it should use course_delete to trigger $format->delete_format_data as a hook 402 */ 403 public function test_delete_format_data(bool $usehook) { 404 global $DB; 405 406 $this->resetAfterTest(); 407 408 $generator = $this->getDataGenerator(); 409 $course = $generator->create_course(); 410 course_create_sections_if_missing($course, [0, 1]); 411 $user = $generator->create_and_enrol($course, 'student'); 412 413 // Create a coursesectionspreferences_XX preference. 414 $key = 'coursesectionspreferences_' . $course->id; 415 $fakevalue = 'No dark sarcasm in the classroom'; 416 set_user_preference($key, $fakevalue, $user->id); 417 $this->assertEquals( 418 $fakevalue, 419 $DB->get_field('user_preferences', 'value', ['name' => $key, 'userid' => $user->id]) 420 ); 421 422 // Create another random user preference. 423 $key2 = 'somepreference'; 424 $fakevalue2 = "All in all it's just another brick in the wall"; 425 set_user_preference($key2, $fakevalue2, $user->id); 426 $this->assertEquals( 427 $fakevalue2, 428 $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id]) 429 ); 430 431 if ($usehook) { 432 delete_course($course, false); 433 } else { 434 $format = course_get_format($course); 435 $format->delete_format_data(); 436 } 437 438 // Check which the preferences exists. 439 $this->assertFalse( 440 $DB->record_exists('user_preferences', ['name' => $key, 'userid' => $user->id]) 441 ); 442 set_user_preference($key2, $fakevalue2, $user->id); 443 $this->assertEquals( 444 $fakevalue2, 445 $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id]) 446 ); 447 } 448 449 /** 450 * Data provider for test_delete_format_data. 451 * 452 * @return array the testing scenarios 453 */ 454 public function delete_format_data_provider(): array { 455 return [ 456 'direct call' => [ 457 'usehook' => false 458 ], 459 'use hook' => [ 460 'usehook' => true, 461 ] 462 ]; 463 } 464 465 /** 466 * Test duplicate_section() 467 * @covers ::duplicate_section 468 */ 469 public function test_duplicate_section() { 470 global $DB; 471 472 $this->setAdminUser(); 473 $this->resetAfterTest(); 474 475 $generator = $this->getDataGenerator(); 476 $course = $generator->create_course(); 477 $format = course_get_format($course); 478 479 $originalsection = $DB->get_record('course_sections', ['course' => $course->id, 'section' => 1], '*', MUST_EXIST); 480 $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]); 481 $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]); 482 $generator->create_module('page', ['course' => $course, 'section' => $originalsection->section]); 483 484 $originalmodcount = $DB->count_records('course_modules', ['course' => $course->id, 'section' => $originalsection->id]); 485 $this->assertEquals(3, $originalmodcount); 486 487 $modinfo = get_fast_modinfo($course); 488 $sectioninfo = $modinfo->get_section_info($originalsection->section, MUST_EXIST); 489 490 $newsection = $format->duplicate_section($sectioninfo); 491 492 // Verify properties are the same. 493 foreach ($originalsection as $prop => $value) { 494 if ($prop == 'id' || $prop == 'sequence' || $prop == 'section' || $prop == 'timemodified') { 495 continue; 496 } 497 $this->assertEquals($value, $newsection->$prop); 498 } 499 500 $newmodcount = $DB->count_records('course_modules', ['course' => $course->id, 'section' => $newsection->id]); 501 $this->assertEquals($originalmodcount, $newmodcount); 502 } 503 504 /** 505 * Test for the default delete format data behaviour. 506 * 507 * @covers ::get_format_string 508 * @dataProvider get_format_string_provider 509 * @param string $key the string key 510 * @param string|null $data any string data 511 * @param array|null $expectedstring the expected string (null for exception) 512 */ 513 public function test_get_format_string(string $key, ?string $data, ?array $expectedstring) { 514 global $DB; 515 516 $this->resetAfterTest(); 517 518 $generator = $this->getDataGenerator(); 519 $course = $generator->create_course(['format' => 'topics']); 520 521 if ($expectedstring) { 522 $expected = get_string($expectedstring[0], $expectedstring[1], $expectedstring[2]); 523 } else { 524 $this->expectException(\coding_exception::class); 525 } 526 $format = course_get_format($course); 527 $result = $format->get_format_string($key, $data); 528 $this->assertEquals($expected, $result); 529 } 530 531 /** 532 * Data provider for test_get_format_string. 533 * 534 * @return array the testing scenarios 535 */ 536 public function get_format_string_provider(): array { 537 return [ 538 'Existing in format lang' => [ 539 'key' => 'sectionsdelete', 540 'data' => null, 541 'expectedstring' => ['sectionsdelete', 'format_topics', null], 542 ], 543 'Not existing in format lang' => [ 544 'key' => 'bulkedit', 545 'data' => null, 546 'expectedstring' => ['bulkedit', 'core_courseformat', null], 547 ], 548 'Existing in format lang with data' => [ 549 'key' => 'selectsection', 550 'data' => 'Example', 551 'expectedstring' => ['selectsection', 'format_topics', 'Example'], 552 ], 553 'Not existing in format lang with data' => [ 554 'key' => 'bulkselection', 555 'data' => 'X', 556 'expectedstring' => ['bulkselection', 'core_courseformat', 'X'], 557 ], 558 'Non existing string' => [ 559 'key' => '%&non_existing_string_in_lang_files$%@#', 560 'data' => null, 561 'expectedstring' => null, 562 ], 563 ]; 564 } 565 566 /** 567 * Test for the move_section_after method. 568 * 569 * @covers ::move_section_after 570 * @dataProvider move_section_after_provider 571 * @param string $movesection the reference of the section to move 572 * @param string $destination the reference of the destination section 573 * @param string[] $order the references of the final section order 574 */ 575 public function test_move_section_after(string $movesection, string $destination, array $order) { 576 global $DB; 577 578 $this->resetAfterTest(); 579 580 $generator = $this->getDataGenerator(); 581 $course = $generator->create_course(); 582 course_create_sections_if_missing($course, [0, 1, 2, 3, 4, 5]); 583 584 $format = course_get_format($course); 585 $modinfo = $format->get_modinfo(); 586 $sectionsinfo = $modinfo->get_section_info_all(); 587 588 $references = []; 589 foreach ($sectionsinfo as $section) { 590 $references["section{$section->section}"] = $section; 591 } 592 593 $result = $format->move_section_after( 594 $references[$movesection], 595 $references[$destination] 596 ); 597 $this->assertEquals(true, $result); 598 // Check the updated course section list. 599 $modinfo = $format->get_modinfo(); 600 $sectionsinfo = $modinfo->get_section_info_all(); 601 $this->assertCount(count($order), $sectionsinfo); 602 foreach ($sectionsinfo as $key => $section) { 603 $sectionreference = $order[$key]; 604 $oldinfo = $references[$sectionreference]; 605 $this->assertEquals($oldinfo->id, $section->id); 606 } 607 } 608 609 /** 610 * Data provider for test_move_section_after. 611 * 612 * @return array the testing scenarios 613 */ 614 public function move_section_after_provider(): array { 615 return [ 616 'Move top' => [ 617 'movesection' => 'section3', 618 'destination' => 'section0', 619 'order' => [ 620 'section0', 621 'section3', 622 'section1', 623 'section2', 624 'section4', 625 'section5', 626 ], 627 ], 628 'Move up' => [ 629 'movesection' => 'section3', 630 'destination' => 'section1', 631 'order' => [ 632 'section0', 633 'section1', 634 'section3', 635 'section2', 636 'section4', 637 'section5', 638 ], 639 ], 640 'Do not move' => [ 641 'movesection' => 'section3', 642 'destination' => 'section2', 643 'order' => [ 644 'section0', 645 'section1', 646 'section2', 647 'section3', 648 'section4', 649 'section5', 650 ], 651 ], 652 'Same position' => [ 653 'movesection' => 'section3', 654 'destination' => 'section3', 655 'order' => [ 656 'section0', 657 'section1', 658 'section2', 659 'section3', 660 'section4', 661 'section5', 662 ], 663 ], 664 'Move down' => [ 665 'movesection' => 'section3', 666 'destination' => 'section4', 667 'order' => [ 668 'section0', 669 'section1', 670 'section2', 671 'section4', 672 'section3', 673 'section5', 674 ], 675 ], 676 'Move bottom' => [ 677 'movesection' => 'section3', 678 'destination' => 'section5', 679 'order' => [ 680 'section0', 681 'section1', 682 'section2', 683 'section4', 684 'section5', 685 'section3', 686 ], 687 ], 688 ]; 689 } 690 691 /** 692 * Test for the get_non_ajax_cm_action_url method. 693 * 694 * @covers ::get_non_ajax_cm_action_url 695 * @dataProvider get_non_ajax_cm_action_url_provider 696 * @param string $action the ajax action name 697 * @param string $expectedparam the expected param to check 698 * @param string $exception if an exception is expected 699 */ 700 public function test_get_non_ajax_cm_action_url(string $action, string $expectedparam, bool $exception) { 701 global $DB; 702 703 $this->resetAfterTest(); 704 705 $generator = $this->getDataGenerator(); 706 $course = $generator->create_course(); 707 $assign0 = $generator->create_module('assign', array('course' => $course, 'section' => 0)); 708 709 $format = course_get_format($course); 710 $modinfo = $format->get_modinfo(); 711 $cminfo = $modinfo->get_cm($assign0->cmid); 712 713 if ($exception) { 714 $this->expectException(\coding_exception::class); 715 } 716 $result = $format->get_non_ajax_cm_action_url($action, $cminfo); 717 $this->assertEquals($assign0->cmid, $result->param($expectedparam)); 718 } 719 720 /** 721 * Data provider for test_get_non_ajax_cm_action_url. 722 * 723 * @return array the testing scenarios 724 */ 725 public function get_non_ajax_cm_action_url_provider(): array { 726 return [ 727 'duplicate' => [ 728 'action' => 'cmDuplicate', 729 'expectedparam' => 'duplicate', 730 'exception' => false, 731 ], 732 'hide' => [ 733 'action' => 'cmHide', 734 'expectedparam' => 'hide', 735 'exception' => false, 736 ], 737 'show' => [ 738 'action' => 'cmShow', 739 'expectedparam' => 'show', 740 'exception' => false, 741 ], 742 'stealth' => [ 743 'action' => 'cmStealth', 744 'expectedparam' => 'stealth', 745 'exception' => false, 746 ], 747 'delete' => [ 748 'action' => 'cmDelete', 749 'expectedparam' => 'delete', 750 'exception' => false, 751 ], 752 'non-existent' => [ 753 'action' => 'nonExistent', 754 'expectedparam' => '', 755 'exception' => true, 756 ], 757 ]; 758 } 759 } 760 761 /** 762 * Class format_testformat. 763 * 764 * A test class that simulates a course format that doesn't define 'news_items' in default blocks. 765 * 766 * @copyright 2016 Jun Pataleta <jun@moodle.com> 767 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 768 */ 769 class format_testformat extends core_courseformat\base { 770 /** 771 * Returns the list of blocks to be automatically added for the newly created course. 772 * 773 * @return array 774 */ 775 public function get_default_blocks() { 776 return [ 777 BLOCK_POS_RIGHT => [], 778 BLOCK_POS_LEFT => [] 779 ]; 780 } 781 } 782 783 /** 784 * Class format_testformatsections. 785 * 786 * A test class that simulates a course format with sections. 787 * 788 * @package core_courseformat 789 * @copyright 2023 ISB Bayern 790 * @author Philipp Memmel 791 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 792 */ 793 class format_testformatsections extends core_courseformat\base { 794 /** 795 * Returns if this course format uses sections. 796 * 797 * @return true 798 */ 799 public function uses_sections() { 800 return true; 801 } 802 } 803 804 /** 805 * Class format_testlegacy. 806 * 807 * A test class that simulates old course formats that define 'news_items' in default blocks. 808 * 809 * @copyright 2016 Jun Pataleta <jun@moodle.com> 810 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 811 */ 812 class format_testlegacy extends core_courseformat\base { 813 /** 814 * Returns the list of blocks to be automatically added for the newly created course. 815 * 816 * @return array 817 */ 818 public function get_default_blocks() { 819 return [ 820 BLOCK_POS_RIGHT => ['news_items'], 821 BLOCK_POS_LEFT => [] 822 ]; 823 } 824 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body