Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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 defined('MOODLE_INTERNAL') || die(); 18 19 /** 20 * Course related unit tests 21 * 22 * @package core_course 23 * @copyright 2014 Marina Glancy 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 class base_test extends advanced_testcase { 27 28 /** 29 * Setup to ensure that fixtures are loaded. 30 */ 31 public static function setupBeforeClass(): void { 32 global $CFG; 33 require_once($CFG->dirroot . '/course/lib.php'); 34 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest.php'); 35 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_state.php'); 36 require_once($CFG->dirroot . '/course/format/tests/fixtures/format_theunittest_output_course_format_invalidoutput.php'); 37 } 38 39 /** 40 * Tests the save and load functionality. 41 * 42 * @author Jason den Dulk 43 * @covers \core_courseformat 44 */ 45 public function test_courseformat_saveandload() { 46 $this->resetAfterTest(); 47 48 $courseformatoptiondata = (object) [ 49 "hideoddsections" => 1, 50 'summary_editor' => [ 51 'text' => '<p>Somewhere over the rainbow</p><p>The <b>quick</b> brown fox jumpos over the lazy dog.</p>', 52 'format' => 1 53 ] 54 ]; 55 $generator = $this->getDataGenerator(); 56 $course1 = $generator->create_course(array('format' => 'theunittest')); 57 $this->assertEquals('theunittest', $course1->format); 58 course_create_sections_if_missing($course1, array(0, 1)); 59 60 $courseformat = course_get_format($course1); 61 $courseformat->update_course_format_options($courseformatoptiondata); 62 63 $savedcourseformatoptiondata = $courseformat->get_format_options(); 64 65 $this->assertEqualsCanonicalizing($courseformatoptiondata, (object) $savedcourseformatoptiondata); 66 } 67 68 public function test_available_hook() { 69 global $DB; 70 $this->resetAfterTest(); 71 72 // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'theunittest'. 73 $generator = $this->getDataGenerator(); 74 $course1 = $generator->create_course(array('format' => 'theunittest')); 75 $this->assertEquals('theunittest', $course1->format); 76 course_create_sections_if_missing($course1, array(0, 1)); 77 $assign0 = $generator->create_module('assign', array('course' => $course1, 'section' => 0)); 78 $assign1 = $generator->create_module('assign', array('course' => $course1, 'section' => 1)); 79 $assign2 = $generator->create_module('assign', array('course' => $course1, 'section' => 0, 'visible' => 0)); 80 81 // Create a courseoverview role based on the student role. 82 $roleattr = array('name' => 'courseoverview', 'shortname' => 'courseoverview', 'archetype' => 'student'); 83 $generator->create_role($roleattr); 84 85 // Create user student, editingteacher, teacher and courseoverview. 86 $student = $generator->create_user(); 87 $teacher = $generator->create_user(); 88 $editingteacher = $generator->create_user(); 89 $courseoverviewuser = $generator->create_user(); 90 91 // Enrol users into their roles. 92 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); 93 $generator->enrol_user($student->id, $course1->id, $roleids['student']); 94 $generator->enrol_user($teacher->id, $course1->id, $roleids['teacher']); 95 $generator->enrol_user($editingteacher->id, $course1->id, $roleids['editingteacher']); 96 $generator->enrol_user($courseoverviewuser->id, $course1->id, $roleids['courseoverview']); 97 98 // Remove the ignoreavailabilityrestrictions from the teacher role. 99 role_change_permission($roleids['teacher'], context_system::instance(0), 100 'moodle/course:ignoreavailabilityrestrictions', CAP_PREVENT); 101 102 // Allow the courseoverview role to ingore available restriction. 103 role_change_permission($roleids['courseoverview'], context_system::instance(0), 104 'moodle/course:ignoreavailabilityrestrictions', CAP_ALLOW); 105 106 // Make sure that initially both sections and both modules are available and visible for a student. 107 $modinfostudent = get_fast_modinfo($course1, $student->id); 108 $this->assertTrue($modinfostudent->get_section_info(1)->available); 109 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 110 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 111 $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->available); 112 $this->assertTrue($modinfostudent->get_cm($assign1->cmid)->uservisible); 113 $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible); 114 115 // Set 'hideoddsections' for the course to 1. 116 // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher. 117 $data = (object)array('id' => $course1->id, 'hideoddsections' => 1); 118 course_get_format($course1)->update_course_format_options($data); 119 $modinfostudent = get_fast_modinfo($course1, $student->id); 120 $this->assertFalse($modinfostudent->get_section_info(1)->available); 121 $this->assertEmpty($modinfostudent->get_section_info(1)->availableinfo); 122 $this->assertFalse($modinfostudent->get_section_info(1)->uservisible); 123 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 124 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 125 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available); 126 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible); 127 $this->assertFalse($modinfostudent->get_cm($assign2->cmid)->uservisible); 128 129 $modinfoteacher = get_fast_modinfo($course1, $teacher->id); 130 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 131 $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo); 132 $this->assertFalse($modinfoteacher->get_section_info(1)->uservisible); 133 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 134 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 135 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 136 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->uservisible); 137 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->available); 138 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible); 139 140 $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id); 141 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 142 $this->assertEmpty($modinfoteacher->get_section_info(1)->availableinfo); 143 $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible); 144 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 145 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 146 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 147 $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible); 148 $this->assertTrue($modinfoteacher->get_cm($assign2->cmid)->uservisible); 149 150 $modinfocourseoverview = get_fast_modinfo($course1, $courseoverviewuser->id); 151 $this->assertFalse($modinfocourseoverview->get_section_info(1)->available); 152 $this->assertEmpty($modinfocourseoverview->get_section_info(1)->availableinfo); 153 $this->assertTrue($modinfocourseoverview->get_section_info(1)->uservisible); 154 $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->available); 155 $this->assertTrue($modinfocourseoverview->get_cm($assign0->cmid)->uservisible); 156 $this->assertFalse($modinfocourseoverview->get_cm($assign1->cmid)->available); 157 $this->assertTrue($modinfocourseoverview->get_cm($assign1->cmid)->uservisible); 158 $this->assertFalse($modinfocourseoverview->get_cm($assign2->cmid)->uservisible); 159 160 // Set 'hideoddsections' for the course to 2. 161 // Section1 and assign1 will be unavailable, uservisible will be false for student and true for teacher. 162 // Property availableinfo will be not empty. 163 $data = (object)array('id' => $course1->id, 'hideoddsections' => 2); 164 course_get_format($course1)->update_course_format_options($data); 165 $modinfostudent = get_fast_modinfo($course1, $student->id); 166 $this->assertFalse($modinfostudent->get_section_info(1)->available); 167 $this->assertNotEmpty($modinfostudent->get_section_info(1)->availableinfo); 168 $this->assertFalse($modinfostudent->get_section_info(1)->uservisible); 169 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->available); 170 $this->assertTrue($modinfostudent->get_cm($assign0->cmid)->uservisible); 171 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->available); 172 $this->assertFalse($modinfostudent->get_cm($assign1->cmid)->uservisible); 173 174 $modinfoteacher = get_fast_modinfo($course1, $editingteacher->id); 175 $this->assertFalse($modinfoteacher->get_section_info(1)->available); 176 $this->assertNotEmpty($modinfoteacher->get_section_info(1)->availableinfo); 177 $this->assertTrue($modinfoteacher->get_section_info(1)->uservisible); 178 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->available); 179 $this->assertTrue($modinfoteacher->get_cm($assign0->cmid)->uservisible); 180 $this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available); 181 $this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible); 182 } 183 184 /** 185 * Test for supports_news() with a course format plugin that doesn't define 'news_items' in default blocks. 186 */ 187 public function test_supports_news() { 188 $this->resetAfterTest(); 189 $format = course_get_format((object)['format' => 'testformat']); 190 $this->assertFalse($format->supports_news()); 191 } 192 193 /** 194 * Test for supports_news() for old course format plugins that defines 'news_items' in default blocks. 195 */ 196 public function test_supports_news_legacy() { 197 $this->resetAfterTest(); 198 $format = course_get_format((object)['format' => 'testlegacy']); 199 $this->assertTrue($format->supports_news()); 200 } 201 202 /** 203 * Test for get_view_url() to ensure that the url is only given for the correct cases 204 */ 205 public function test_get_view_url() { 206 global $CFG; 207 $this->resetAfterTest(); 208 209 $linkcoursesections = $CFG->linkcoursesections; 210 211 // Generate a course with two sections (0 and 1) and two modules. Course format is set to 'testformat'. 212 // This will allow us to test the default implementation of get_view_url. 213 $generator = $this->getDataGenerator(); 214 $course1 = $generator->create_course(array('format' => 'testformat')); 215 course_create_sections_if_missing($course1, array(0, 1)); 216 217 $data = (object)['id' => $course1->id]; 218 $format = course_get_format($course1); 219 $format->update_course_format_options($data); 220 221 // In page. 222 $CFG->linkcoursesections = 0; 223 $this->assertNotEmpty($format->get_view_url(null)); 224 $this->assertNotEmpty($format->get_view_url(0)); 225 $this->assertNotEmpty($format->get_view_url(1)); 226 $CFG->linkcoursesections = 1; 227 $this->assertNotEmpty($format->get_view_url(null)); 228 $this->assertNotEmpty($format->get_view_url(0)); 229 $this->assertNotEmpty($format->get_view_url(1)); 230 231 // Navigation. 232 $CFG->linkcoursesections = 0; 233 $this->assertNull($format->get_view_url(1, ['navigation' => 1])); 234 $this->assertNull($format->get_view_url(0, ['navigation' => 1])); 235 $CFG->linkcoursesections = 1; 236 $this->assertNotEmpty($format->get_view_url(1, ['navigation' => 1])); 237 $this->assertNotEmpty($format->get_view_url(0, ['navigation' => 1])); 238 } 239 240 /** 241 * Test for get_output_classname method. 242 * 243 * @dataProvider get_output_classname_provider 244 * @param string $find the class to find 245 * @param string $result the expected result classname 246 * @param bool $exception if the method will raise an exception 247 */ 248 public function test_get_output_classname($find, $result, $exception) { 249 $this->resetAfterTest(); 250 251 $course = $this->getDataGenerator()->create_course(['format' => 'theunittest']); 252 $courseformat = course_get_format($course); 253 254 if ($exception) { 255 $this->expectException(coding_exception::class); 256 } 257 258 $courseclass = $courseformat->get_output_classname($find); 259 $this->assertEquals($result, $courseclass); 260 } 261 262 /** 263 * Data provider for test_get_output_classname. 264 * 265 * @return array the testing scenarios 266 */ 267 public function get_output_classname_provider(): array { 268 return [ 269 'overridden class' => [ 270 'find' => 'state\\course', 271 'result' => 'format_theunittest\\output\\courseformat\\state\\course', 272 'exception' => false, 273 ], 274 'original class' => [ 275 'find' => 'state\\section', 276 'result' => 'core_courseformat\\output\\local\\state\\section', 277 'exception' => false, 278 ], 279 'invalid overridden class' => [ 280 'find' => 'state\\invalidoutput', 281 'result' => '', 282 'exception' => true, 283 ], 284 ]; 285 } 286 287 /** 288 * Test for the default delete format data behaviour. 289 * 290 * @covers ::get_sections_preferences 291 */ 292 public function test_get_sections_preferences() { 293 $this->resetAfterTest(); 294 $generator = $this->getDataGenerator(); 295 $course = $generator->create_course(); 296 $user = $generator->create_and_enrol($course, 'student'); 297 298 // Create fake preferences generated by the frontend js module. 299 $data = (object)[ 300 'pref1' => [1,2], 301 'pref2' => [1], 302 ]; 303 set_user_preference('coursesectionspreferences_' . $course->id, json_encode($data), $user->id); 304 305 $format = course_get_format($course); 306 307 // Load data from user 1. 308 $this->setUser($user); 309 $preferences = $format->get_sections_preferences(); 310 311 $this->assertEquals( 312 (object)['pref1' => true, 'pref2' => true], 313 $preferences[1] 314 ); 315 $this->assertEquals( 316 (object)['pref1' => true], 317 $preferences[2] 318 ); 319 } 320 321 /** 322 * Test for the default delete format data behaviour. 323 * 324 * @covers ::set_sections_preference 325 */ 326 public function test_set_sections_preference() { 327 $this->resetAfterTest(); 328 $generator = $this->getDataGenerator(); 329 $course = $generator->create_course(); 330 $user = $generator->create_and_enrol($course, 'student'); 331 332 $format = course_get_format($course); 333 $this->setUser($user); 334 335 // Load data from user 1. 336 $format->set_sections_preference('pref1', [1, 2]); 337 $format->set_sections_preference('pref2', [1]); 338 $format->set_sections_preference('pref3', []); 339 340 $preferences = $format->get_sections_preferences(); 341 $this->assertEquals( 342 (object)['pref1' => true, 'pref2' => true], 343 $preferences[1] 344 ); 345 $this->assertEquals( 346 (object)['pref1' => true], 347 $preferences[2] 348 ); 349 } 350 351 /** 352 * Test for the default delete format data behaviour. 353 * 354 * @covers ::delete_format_data 355 * @dataProvider delete_format_data_provider 356 * @param bool $usehook if it should use course_delete to trigger $format->delete_format_data as a hook 357 */ 358 public function test_delete_format_data(bool $usehook) { 359 global $DB; 360 361 $this->resetAfterTest(); 362 363 $generator = $this->getDataGenerator(); 364 $course = $generator->create_course(); 365 course_create_sections_if_missing($course, [0, 1]); 366 $user = $generator->create_and_enrol($course, 'student'); 367 368 // Create a coursesectionspreferences_XX preference. 369 $key = 'coursesectionspreferences_' . $course->id; 370 $fakevalue = 'No dark sarcasm in the classroom'; 371 set_user_preference($key, $fakevalue, $user->id); 372 $this->assertEquals( 373 $fakevalue, 374 $DB->get_field('user_preferences', 'value', ['name' => $key, 'userid' => $user->id]) 375 ); 376 377 // Create another random user preference. 378 $key2 = 'somepreference'; 379 $fakevalue2 = "All in all it's just another brick in the wall"; 380 set_user_preference($key2, $fakevalue2, $user->id); 381 $this->assertEquals( 382 $fakevalue2, 383 $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id]) 384 ); 385 386 if ($usehook) { 387 delete_course($course, false); 388 } else { 389 $format = course_get_format($course); 390 $format->delete_format_data(); 391 } 392 393 // Check which the preferences exists. 394 $this->assertFalse( 395 $DB->record_exists('user_preferences', ['name' => $key, 'userid' => $user->id]) 396 ); 397 set_user_preference($key2, $fakevalue2, $user->id); 398 $this->assertEquals( 399 $fakevalue2, 400 $DB->get_field('user_preferences', 'value', ['name' => $key2, 'userid' => $user->id]) 401 ); 402 } 403 404 /** 405 * Data provider for test_delete_format_data. 406 * 407 * @return array the testing scenarios 408 */ 409 public function delete_format_data_provider(): array { 410 return [ 411 'direct call' => [ 412 'usehook' => false 413 ], 414 'use hook' => [ 415 'usehook' => true, 416 ] 417 ]; 418 } 419 } 420 421 /** 422 * Class format_testformat. 423 * 424 * A test class that simulates a course format that doesn't define 'news_items' in default blocks. 425 * 426 * @copyright 2016 Jun Pataleta <jun@moodle.com> 427 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 428 */ 429 class format_testformat extends core_courseformat\base { 430 /** 431 * Returns the list of blocks to be automatically added for the newly created course. 432 * 433 * @return array 434 */ 435 public function get_default_blocks() { 436 return [ 437 BLOCK_POS_RIGHT => [], 438 BLOCK_POS_LEFT => [] 439 ]; 440 } 441 } 442 443 /** 444 * Class format_testlegacy. 445 * 446 * A test class that simulates old course formats that define 'news_items' in default blocks. 447 * 448 * @copyright 2016 Jun Pataleta <jun@moodle.com> 449 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 450 */ 451 class format_testlegacy extends core_courseformat\base { 452 /** 453 * Returns the list of blocks to be automatically added for the newly created course. 454 * 455 * @return array 456 */ 457 public function get_default_blocks() { 458 return [ 459 BLOCK_POS_RIGHT => ['news_items'], 460 BLOCK_POS_LEFT => [] 461 ]; 462 } 463 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body