See Release Notes
Long Term Support Release
Differences Between: [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 namespace core_courseformat; 18 19 use moodle_exception; 20 use stdClass; 21 22 /** 23 * Tests for the stateactions class. 24 * 25 * @package core_courseformat 26 * @category test 27 * @copyright 2021 Sara Arjona (sara@moodle.com) 28 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 29 * @coversDefaultClass \core_courseformat\stateactions 30 */ 31 class stateactions_test extends \advanced_testcase { 32 33 /** 34 * Setup to ensure that fixtures are loaded. 35 */ 36 public static function setupBeforeClass(): void { 37 global $CFG; 38 require_once($CFG->dirroot . '/lib/externallib.php'); 39 } 40 41 /** 42 * Helper method to create an activity into a section and add it to the $sections and $activities arrays. 43 * 44 * @param int $courseid Course identifier where the activity will be added. 45 * @param string $type Activity type ('forum', 'assign', ...). 46 * @param int $section Section number where the activity will be added. 47 * @param bool $visible Whether the activity will be visible or not. 48 * @return int the activity cm id 49 */ 50 private function create_activity( 51 int $courseid, 52 string $type, 53 int $section, 54 bool $visible = true 55 ): int { 56 57 $activity = $this->getDataGenerator()->create_module( 58 $type, 59 ['course' => $courseid], 60 [ 61 'section' => $section, 62 'visible' => $visible 63 ] 64 ); 65 return $activity->cmid; 66 } 67 68 /** 69 * Helper to create a course and generate a section list. 70 * 71 * @param string $format the course format 72 * @param int $sections the number of sections 73 * @param int[] $hiddensections the section numbers to hide 74 * @return stdClass the course object 75 */ 76 private function create_course(string $format, int $sections, array $hiddensections): stdClass { 77 global $DB; 78 79 $course = $this->getDataGenerator()->create_course(['numsections' => $sections, 'format' => $format]); 80 foreach ($hiddensections as $section) { 81 set_section_visible($course->id, $section, 0); 82 } 83 84 return $course; 85 } 86 87 /** 88 * Return an array if the course references. 89 * 90 * This method is used to create alias to sections and other stuff in the dataProviders. 91 * 92 * @param stdClass $course the course object 93 * @return int[] a relation betwee all references and its element id 94 */ 95 private function course_references(stdClass $course): array { 96 global $DB; 97 98 $references = []; 99 100 $sectionrecords = $DB->get_records('course_sections', ['course' => $course->id]); 101 foreach ($sectionrecords as $id => $section) { 102 $references["section{$section->section}"] = $section->id; 103 } 104 $references['course'] = $course->id; 105 $references['invalidsection'] = -1; 106 $references['invalidcm'] = -1; 107 108 return $references; 109 } 110 111 /** 112 * Translate a references array into current ids. 113 * 114 * @param string[] $references the references list 115 * @param string[] $values the values to translate 116 * @return int[] the list of ids 117 */ 118 private function translate_references(array $references, array $values): array { 119 $result = []; 120 foreach ($values as $value) { 121 $result[] = $references[$value]; 122 } 123 return $result; 124 } 125 126 /** 127 * Generate a sorted and summarized list of an state updates message. 128 * 129 * It is important to note that the order in the update messages are not important in a real scenario 130 * because each message affects a specific part of the course state. However, for the PHPUnit test 131 * have them sorted and classified simplifies the asserts. 132 * 133 * @param stateupdates $updateobj the state updates object 134 * @return array of all data updates. 135 */ 136 private function summarize_updates(stateupdates $updateobj): array { 137 // Check state returned after executing given action. 138 $updatelist = $updateobj->jsonSerialize(); 139 140 // Initial summary structure. 141 $result = [ 142 'create' => [ 143 'course' => [], 144 'section' => [], 145 'cm' => [], 146 'count' => 0, 147 ], 148 'put' => [ 149 'course' => [], 150 'section' => [], 151 'cm' => [], 152 'count' => 0, 153 ], 154 'remove' => [ 155 'course' => [], 156 'section' => [], 157 'cm' => [], 158 'count' => 0, 159 ], 160 ]; 161 foreach ($updatelist as $update) { 162 if (!isset($result[$update->action])) { 163 $result[$update->action] = [ 164 'course' => [], 165 'section' => [], 166 'cm' => [], 167 'count' => 0, 168 ]; 169 } 170 $elementid = $update->fields->id ?? 0; 171 $result[$update->action][$update->name][$elementid] = $update->fields; 172 $result[$update->action]['count']++; 173 } 174 return $result; 175 } 176 177 /** 178 * Test the behaviour course_state. 179 * 180 * @dataProvider get_state_provider 181 * @covers ::course_state 182 * @covers ::section_state 183 * @covers ::cm_state 184 * 185 * @param string $format The course will be created with this course format. 186 * @param string $role The role of the user that will execute the method. 187 * @param string $method the method to call 188 * @param array $params the ids, targetsection and targetcm to use as params 189 * @param array $expectedresults List of the course module names expected after calling the method. 190 * @param bool $expectedexception If this call will raise an exception. 191 192 */ 193 public function test_get_state( 194 string $format, 195 string $role, 196 string $method, 197 array $params, 198 array $expectedresults, 199 bool $expectedexception = false 200 ): void { 201 202 $this->resetAfterTest(); 203 204 // Create a course with 3 sections, 1 of them hidden. 205 $course = $this->create_course($format, 3, [2]); 206 207 $references = $this->course_references($course); 208 209 // Create and enrol user using given role. 210 if ($role == 'admin') { 211 $this->setAdminUser(); 212 } else { 213 $user = $this->getDataGenerator()->create_user(); 214 if ($role != 'unenroled') { 215 $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); 216 } 217 $this->setUser($user); 218 } 219 220 // Add some activities to the course. One visible and one hidden in both sections 1 and 2. 221 $references["cm0"] = $this->create_activity($course->id, 'assign', 1, true); 222 $references["cm1"] = $this->create_activity($course->id, 'book', 1, false); 223 $references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true); 224 $references["cm3"] = $this->create_activity($course->id, 'page', 2, false); 225 226 if ($expectedexception) { 227 $this->expectException(moodle_exception::class); 228 } 229 230 // Initialise stateupdates. 231 $courseformat = course_get_format($course->id); 232 $updates = new stateupdates($courseformat); 233 234 // Execute given method. 235 $actions = new stateactions(); 236 $actions->$method( 237 $updates, 238 $course, 239 $this->translate_references($references, $params['ids']), 240 $references[$params['targetsectionid']] ?? null, 241 $references[$params['targetcmid']] ?? null 242 ); 243 244 // Format results in a way we can compare easily. 245 $results = $this->summarize_updates($updates); 246 247 // The state actions does not use create or remove actions because they are designed 248 // to refresh parts of the state. 249 $this->assertEquals(0, $results['create']['count']); 250 $this->assertEquals(0, $results['remove']['count']); 251 252 // Validate we have all the expected entries. 253 $expectedtotal = count($expectedresults['course']) + count($expectedresults['section']) + count($expectedresults['cm']); 254 $this->assertEquals($expectedtotal, $results['put']['count']); 255 256 // Validate course, section and cm. 257 foreach ($expectedresults as $name => $referencekeys) { 258 foreach ($referencekeys as $referencekey) { 259 $this->assertArrayHasKey($references[$referencekey], $results['put'][$name]); 260 } 261 } 262 } 263 264 /** 265 * Data provider for data request creation tests. 266 * 267 * @return array the testing scenarios 268 */ 269 public function get_state_provider(): array { 270 return array_merge( 271 $this->course_state_provider('weeks'), 272 $this->course_state_provider('topics'), 273 $this->course_state_provider('social'), 274 $this->section_state_provider('weeks', 'admin'), 275 $this->section_state_provider('weeks', 'editingteacher'), 276 $this->section_state_provider('weeks', 'student'), 277 $this->section_state_provider('topics', 'admin'), 278 $this->section_state_provider('topics', 'editingteacher'), 279 $this->section_state_provider('topics', 'student'), 280 $this->section_state_provider('social', 'admin'), 281 $this->section_state_provider('social', 'editingteacher'), 282 $this->section_state_provider('social', 'student'), 283 $this->cm_state_provider('weeks', 'admin'), 284 $this->cm_state_provider('weeks', 'editingteacher'), 285 $this->cm_state_provider('weeks', 'student'), 286 $this->cm_state_provider('topics', 'admin'), 287 $this->cm_state_provider('topics', 'editingteacher'), 288 $this->cm_state_provider('topics', 'student'), 289 $this->cm_state_provider('social', 'admin'), 290 $this->cm_state_provider('social', 'editingteacher'), 291 $this->cm_state_provider('social', 'student'), 292 ); 293 } 294 295 /** 296 * Course state data provider. 297 * 298 * @param string $format the course format 299 * @return array the testing scenarios 300 */ 301 public function course_state_provider(string $format): array { 302 $expectedexception = ($format === 'social'); 303 return [ 304 // Tests for course_state. 305 "admin $format course_state" => [ 306 'format' => $format, 307 'role' => 'admin', 308 'method' => 'course_state', 309 'params' => [ 310 'ids' => [], 'targetsectionid' => null, 'targetcmid' => null 311 ], 312 'expectedresults' => [ 313 'course' => ['course'], 314 'section' => ['section0', 'section1', 'section2', 'section3'], 315 'cm' => ['cm0', 'cm1', 'cm2', 'cm3'], 316 ], 317 'expectedexception' => $expectedexception, 318 ], 319 "editingteacher $format course_state" => [ 320 'format' => $format, 321 'role' => 'editingteacher', 322 'method' => 'course_state', 323 'params' => [ 324 'ids' => [], 'targetsectionid' => null, 'targetcmid' => null 325 ], 326 'expectedresults' => [ 327 'course' => ['course'], 328 'section' => ['section0', 'section1', 'section2', 'section3'], 329 'cm' => ['cm0', 'cm1', 'cm2', 'cm3'], 330 ], 331 'expectedexception' => $expectedexception, 332 ], 333 "student $format course_state" => [ 334 'format' => $format, 335 'role' => 'student', 336 'method' => 'course_state', 337 'params' => [ 338 'ids' => [], 'targetsectionid' => null, 'targetcmid' => null 339 ], 340 'expectedresults' => [ 341 'course' => ['course'], 342 'section' => ['section0', 'section1', 'section3'], 343 'cm' => ['cm0'], 344 ], 345 'expectedexception' => $expectedexception, 346 ], 347 ]; 348 } 349 350 /** 351 * Section state data provider. 352 * 353 * @param string $format the course format 354 * @param string $role the user role 355 * @return array the testing scenarios 356 */ 357 public function section_state_provider(string $format, string $role): array { 358 359 // Social format will raise an exception and debug messages because it does not 360 // use sections and it does not provide a renderer. 361 $expectedexception = ($format === 'social'); 362 363 // All sections and cms that the user can access to. 364 $usersections = ['section0', 'section1', 'section2', 'section3']; 365 $usercms = ['cm0', 'cm1', 'cm2', 'cm3']; 366 if ($role == 'student') { 367 $usersections = ['section0', 'section1', 'section3']; 368 $usercms = ['cm0']; 369 } 370 371 return [ 372 "$role $format section_state no section" => [ 373 'format' => $format, 374 'role' => $role, 375 'method' => 'section_state', 376 'params' => [ 377 'ids' => [], 'targetsectionid' => null, 'targetcmid' => null 378 ], 379 'expectedresults' => [], 380 'expectedexception' => true, 381 ], 382 "$role $format section_state section 0" => [ 383 'format' => $format, 384 'role' => $role, 385 'method' => 'section_state', 386 'params' => [ 387 'ids' => ['section0'], 'targetsectionid' => null, 'targetcmid' => null 388 ], 389 'expectedresults' => [ 390 'course' => [], 391 'section' => array_intersect(['section0'], $usersections), 392 'cm' => [], 393 ], 394 'expectedexception' => $expectedexception, 395 ], 396 "$role $format section_state visible section" => [ 397 'format' => $format, 398 'role' => $role, 399 'method' => 'section_state', 400 'params' => [ 401 'ids' => ['section1'], 'targetsectionid' => null, 'targetcmid' => null 402 ], 403 'expectedresults' => [ 404 'course' => [], 405 'section' => array_intersect(['section1'], $usersections), 406 'cm' => array_intersect(['cm0', 'cm1'], $usercms), 407 ], 408 'expectedexception' => $expectedexception, 409 ], 410 "$role $format section_state hidden section" => [ 411 'format' => $format, 412 'role' => $role, 413 'method' => 'section_state', 414 'params' => [ 415 'ids' => ['section2'], 'targetsectionid' => null, 'targetcmid' => null 416 ], 417 'expectedresults' => [ 418 'course' => [], 419 'section' => array_intersect(['section2'], $usersections), 420 'cm' => array_intersect(['cm2', 'cm3'], $usercms), 421 ], 422 'expectedexception' => $expectedexception, 423 ], 424 "$role $format section_state several sections" => [ 425 'format' => $format, 426 'role' => $role, 427 'method' => 'section_state', 428 'params' => [ 429 'ids' => ['section1', 'section3'], 'targetsectionid' => null, 'targetcmid' => null 430 ], 431 'expectedresults' => [ 432 'course' => [], 433 'section' => array_intersect(['section1', 'section3'], $usersections), 434 'cm' => array_intersect(['cm0', 'cm1'], $usercms), 435 ], 436 'expectedexception' => $expectedexception, 437 ], 438 "$role $format section_state invalid section" => [ 439 'format' => $format, 440 'role' => $role, 441 'method' => 'section_state', 442 'params' => [ 443 'ids' => ['invalidsection'], 'targetsectionid' => null, 'targetcmid' => null 444 ], 445 'expectedresults' => [], 446 'expectedexception' => true, 447 ], 448 "$role $format section_state using target section" => [ 449 'format' => $format, 450 'role' => $role, 451 'method' => 'section_state', 452 'params' => [ 453 'ids' => ['section1'], 'targetsectionid' => 'section3', 'targetcmid' => null 454 ], 455 'expectedresults' => [ 456 'course' => [], 457 'section' => array_intersect(['section1', 'section3'], $usersections), 458 'cm' => array_intersect(['cm0', 'cm1'], $usercms), 459 ], 460 'expectedexception' => $expectedexception, 461 ], 462 "$role $format section_state using target targetcmid" => [ 463 'format' => $format, 464 'role' => $role, 465 'method' => 'section_state', 466 'params' => [ 467 'ids' => ['section3'], 'targetsectionid' => null, 'targetcmid' => 'cm1' 468 ], 469 'expectedresults' => [ 470 'course' => [], 471 'section' => array_intersect(['section3'], $usersections), 472 'cm' => array_intersect(['cm1'], $usercms), 473 ], 474 'expectedexception' => $expectedexception, 475 ], 476 ]; 477 } 478 479 /** 480 * Course module state data provider. 481 * 482 * @param string $format the course format 483 * @param string $role the user role 484 * @return array the testing scenarios 485 */ 486 public function cm_state_provider(string $format, string $role): array { 487 488 // All sections and cms that the user can access to. 489 $usersections = ['section0', 'section1', 'section2', 'section3']; 490 $usercms = ['cm0', 'cm1', 'cm2', 'cm3']; 491 if ($role == 'student') { 492 $usersections = ['section0', 'section1', 'section3']; 493 $usercms = ['cm0']; 494 } 495 496 return [ 497 "$role $format cm_state no cms" => [ 498 'format' => $format, 499 'role' => $role, 500 'method' => 'cm_state', 501 'params' => [ 502 'ids' => [], 'targetsectionid' => null, 'targetcmid' => null 503 ], 504 'expectedresults' => [], 505 'expectedexception' => true, 506 ], 507 "$role $format cm_state visible cm" => [ 508 'format' => $format, 509 'role' => $role, 510 'method' => 'cm_state', 511 'params' => [ 512 'ids' => ['cm0'], 'targetsectionid' => null, 'targetcmid' => null 513 ], 514 'expectedresults' => [ 515 'course' => [], 516 'section' => array_intersect(['section1'], $usersections), 517 'cm' => array_intersect(['cm0'], $usercms), 518 ], 519 'expectedexception' => false, 520 ], 521 "$role $format cm_state hidden cm" => [ 522 'format' => $format, 523 'role' => $role, 524 'method' => 'cm_state', 525 'params' => [ 526 'ids' => ['cm1'], 'targetsectionid' => null, 'targetcmid' => null 527 ], 528 'expectedresults' => [ 529 'course' => [], 530 'section' => array_intersect(['section1'], $usersections), 531 'cm' => array_intersect(['cm1'], $usercms), 532 ], 533 'expectedexception' => false, 534 ], 535 "$role $format cm_state several cm" => [ 536 'format' => $format, 537 'role' => $role, 538 'method' => 'cm_state', 539 'params' => [ 540 'ids' => ['cm0', 'cm2'], 'targetsectionid' => null, 'targetcmid' => null 541 ], 542 'expectedresults' => [ 543 'course' => [], 544 'section' => array_intersect(['section1', 'section2'], $usersections), 545 'cm' => array_intersect(['cm0', 'cm2'], $usercms), 546 ], 547 'expectedexception' => false, 548 ], 549 "$role $format cm_state using targetsection" => [ 550 'format' => $format, 551 'role' => $role, 552 'method' => 'cm_state', 553 'params' => [ 554 'ids' => ['cm0'], 'targetsectionid' => 'section2', 'targetcmid' => null 555 ], 556 'expectedresults' => [ 557 'course' => [], 558 'section' => array_intersect(['section1', 'section2'], $usersections), 559 'cm' => array_intersect(['cm0'], $usercms), 560 ], 561 'expectedexception' => ($format === 'social'), 562 ], 563 "$role $format cm_state using targetcm" => [ 564 'format' => $format, 565 'role' => $role, 566 'method' => 'cm_state', 567 'params' => [ 568 'ids' => ['cm0'], 'targetsectionid' => null, 'targetcmid' => 'cm3' 569 ], 570 'expectedresults' => [ 571 'course' => [], 572 'section' => array_intersect(['section1', 'section2'], $usersections), 573 'cm' => array_intersect(['cm0', 'cm3'], $usercms), 574 ], 575 'expectedexception' => false, 576 ], 577 "$role $format cm_state using an invalid cm" => [ 578 'format' => $format, 579 'role' => $role, 580 'method' => 'cm_state', 581 'params' => [ 582 'ids' => ['invalidcm'], 'targetsectionid' => null, 'targetcmid' => null 583 ], 584 'expectedresults' => [], 585 'expectedexception' => true, 586 ], 587 ]; 588 } 589 590 /** 591 * Internal method for testing a specific state action. 592 * 593 * @param string $method the method to test 594 * @param string $role the user role 595 * @param string[] $idrefs the sections or cms id references to be used as method params 596 * @param bool $expectedexception whether the call should throw an exception 597 * @param int $expectedtotal the expected total number of state puts 598 * @param string|null $coursefield the course field to check 599 * @param int|string|null $coursevalue the section field value 600 * @param string|null $sectionfield the section field to check 601 * @param int|string|null $sectionvalue the section field value 602 * @param string|null $cmfield the cm field to check 603 * @param int|string|null $cmvalue the cm field value 604 * @return array the state update summary 605 */ 606 protected function basic_state_text( 607 string $method = 'section_hide', 608 string $role = 'editingteacher', 609 array $idrefs = [], 610 bool $expectedexception = false, 611 int $expectedtotal = 0, 612 ?string $coursefield = null, 613 $coursevalue = 0, 614 ?string $sectionfield = null, 615 $sectionvalue = 0, 616 ?string $cmfield = null, 617 $cmvalue = 0 618 ): array { 619 $this->resetAfterTest(); 620 621 // Create a course with 3 sections, 1 of them hidden. 622 $course = $this->create_course('topics', 3, [2]); 623 624 $references = $this->course_references($course); 625 626 $user = $this->getDataGenerator()->create_user(); 627 $this->getDataGenerator()->enrol_user($user->id, $course->id, $role); 628 $this->setUser($user); 629 630 // Add some activities to the course. One visible and one hidden in both sections 1 and 2. 631 $references["cm0"] = $this->create_activity($course->id, 'assign', 1, true); 632 $references["cm1"] = $this->create_activity($course->id, 'book', 1, false); 633 $references["cm2"] = $this->create_activity($course->id, 'glossary', 2, true); 634 $references["cm3"] = $this->create_activity($course->id, 'page', 2, false); 635 636 if ($expectedexception) { 637 $this->expectException(moodle_exception::class); 638 } 639 640 // Initialise stateupdates. 641 $courseformat = course_get_format($course->id); 642 $updates = new stateupdates($courseformat); 643 644 // Execute the method. 645 $actions = new stateactions(); 646 $actions->$method( 647 $updates, 648 $course, 649 $this->translate_references($references, $idrefs), 650 ); 651 652 // Format results in a way we can compare easily. 653 $results = $this->summarize_updates($updates); 654 655 // Most state actions does not use create or remove actions because they are designed 656 // to refresh parts of the state. 657 $this->assertEquals(0, $results['create']['count']); 658 $this->assertEquals(0, $results['remove']['count']); 659 660 // Validate we have all the expected entries. 661 $this->assertEquals($expectedtotal, $results['put']['count']); 662 663 // Validate course, section and cm. 664 if (!empty($coursefield)) { 665 foreach ($results['put']['course'] as $courseid) { 666 $this->assertEquals($coursevalue, $results['put']['course'][$courseid][$coursefield]); 667 } 668 } 669 if (!empty($sectionfield)) { 670 foreach ($results['put']['section'] as $section) { 671 $this->assertEquals($sectionvalue, $section->$sectionfield); 672 } 673 } 674 if (!empty($cmfield)) { 675 foreach ($results['put']['cm'] as $cm) { 676 $this->assertEquals($cmvalue, $cm->$cmfield); 677 } 678 } 679 return $results; 680 } 681 682 /** 683 * Test for section_hide 684 * 685 * @covers ::section_hide 686 * @dataProvider basic_role_provider 687 * @param string $role the user role 688 * @param bool $expectedexception if it will expect an exception. 689 */ 690 public function test_section_hide( 691 string $role = 'editingteacher', 692 bool $expectedexception = false 693 ): void { 694 $this->basic_state_text( 695 'section_hide', 696 $role, 697 ['section1', 'section2', 'section3'], 698 $expectedexception, 699 7, 700 null, 701 null, 702 'visible', 703 0, 704 null, 705 null 706 ); 707 } 708 709 /** 710 * Test for section_hide 711 * 712 * @covers ::section_show 713 * @dataProvider basic_role_provider 714 * @param string $role the user role 715 * @param bool $expectedexception if it will expect an exception. 716 */ 717 public function test_section_show( 718 string $role = 'editingteacher', 719 bool $expectedexception = false 720 ): void { 721 $this->basic_state_text( 722 'section_show', 723 $role, 724 ['section1', 'section2', 'section3'], 725 $expectedexception, 726 7, 727 null, 728 null, 729 'visible', 730 1, 731 null, 732 null 733 ); 734 } 735 736 /** 737 * Test for cm_show 738 * 739 * @covers ::cm_show 740 * @dataProvider basic_role_provider 741 * @param string $role the user role 742 * @param bool $expectedexception if it will expect an exception. 743 */ 744 public function test_cm_show( 745 string $role = 'editingteacher', 746 bool $expectedexception = false 747 ): void { 748 $this->basic_state_text( 749 'cm_show', 750 $role, 751 ['cm0', 'cm1', 'cm2', 'cm3'], 752 $expectedexception, 753 4, 754 null, 755 null, 756 null, 757 null, 758 'visible', 759 1 760 ); 761 } 762 763 /** 764 * Test for cm_hide 765 * 766 * @covers ::cm_hide 767 * @dataProvider basic_role_provider 768 * @param string $role the user role 769 * @param bool $expectedexception if it will expect an exception. 770 */ 771 public function test_cm_hide( 772 string $role = 'editingteacher', 773 bool $expectedexception = false 774 ): void { 775 $this->basic_state_text( 776 'cm_hide', 777 $role, 778 ['cm0', 'cm1', 'cm2', 'cm3'], 779 $expectedexception, 780 4, 781 null, 782 null, 783 null, 784 null, 785 'visible', 786 0 787 ); 788 } 789 790 /** 791 * Test for cm_stealth 792 * 793 * @covers ::cm_stealth 794 * @dataProvider basic_role_provider 795 * @param string $role the user role 796 * @param bool $expectedexception if it will expect an exception. 797 */ 798 public function test_cm_stealth( 799 string $role = 'editingteacher', 800 bool $expectedexception = false 801 ): void { 802 set_config('allowstealth', 1); 803 $this->basic_state_text( 804 'cm_stealth', 805 $role, 806 ['cm0', 'cm1', 'cm2', 'cm3'], 807 $expectedexception, 808 4, 809 null, 810 null, 811 null, 812 null, 813 'stealth', 814 1 815 ); 816 // Disable stealth. 817 set_config('allowstealth', 0); 818 // When stealth are disabled the validation is a but more complex because they depends 819 // also on the section visibility (legacy stealth). 820 $this->basic_state_text( 821 'cm_stealth', 822 $role, 823 ['cm0', 'cm1'], 824 $expectedexception, 825 2, 826 null, 827 null, 828 null, 829 null, 830 'stealth', 831 0 832 ); 833 $this->basic_state_text( 834 'cm_stealth', 835 $role, 836 ['cm2', 'cm3'], 837 $expectedexception, 838 2, 839 null, 840 null, 841 null, 842 null, 843 'stealth', 844 1 845 ); 846 } 847 848 /** 849 * Data provider for basic role tests. 850 * 851 * @return array the testing scenarios 852 */ 853 public function basic_role_provider() { 854 return [ 855 'editingteacher' => [ 856 'role' => 'editingteacher', 857 'expectedexception' => false, 858 ], 859 'teacher' => [ 860 'role' => 'teacher', 861 'expectedexception' => true, 862 ], 863 'student' => [ 864 'role' => 'student', 865 'expectedexception' => true, 866 ], 867 'guest' => [ 868 'role' => 'guest', 869 'expectedexception' => true, 870 ], 871 ]; 872 } 873 874 /** 875 * Test for cm_moveright 876 * 877 * @covers ::cm_moveright 878 * @dataProvider basic_role_provider 879 * @param string $role the user role 880 * @param bool $expectedexception if it will expect an exception. 881 */ 882 public function test_cm_moveright( 883 string $role = 'editingteacher', 884 bool $expectedexception = false 885 ): void { 886 $this->basic_state_text( 887 'cm_moveright', 888 $role, 889 ['cm0', 'cm1', 'cm2', 'cm3'], 890 $expectedexception, 891 4, 892 null, 893 null, 894 null, 895 null, 896 'indent', 897 1 898 ); 899 } 900 901 /** 902 * Test for cm_moveleft 903 * 904 * @covers ::cm_moveleft 905 * @dataProvider basic_role_provider 906 * @param string $role the user role 907 * @param bool $expectedexception if it will expect an exception. 908 */ 909 public function test_cm_moveleft( 910 string $role = 'editingteacher', 911 bool $expectedexception = false 912 ): void { 913 $this->basic_state_text( 914 'cm_moveleft', 915 $role, 916 ['cm0', 'cm1', 'cm2', 'cm3'], 917 $expectedexception, 918 4, 919 null, 920 null, 921 null, 922 null, 923 'indent', 924 0 925 ); 926 } 927 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body