Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]
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 * Event container tests. 19 * 20 * @package core_calendar 21 * @copyright 2017 Cameron Ball <cameron@cameron1729.xyz> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 global $CFG; 28 29 require_once($CFG->dirroot . '/calendar/lib.php'); 30 31 use core_calendar\local\event\entities\action_event; 32 use core_calendar\local\event\entities\event; 33 use core_calendar\local\event\entities\event_interface; 34 use core_calendar\local\event\factories\event_factory; 35 use core_calendar\local\event\factories\event_factory_interface; 36 use core_calendar\local\event\mappers\event_mapper; 37 use core_calendar\local\event\mappers\event_mapper_interface; 38 39 /** 40 * Core container testcase. 41 * 42 * @copyright 2017 Cameron Ball <cameron@cameron1729.xyz> 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class core_calendar_container_testcase extends advanced_testcase { 46 47 /** 48 * Test setup. 49 */ 50 public function setUp(): void { 51 $this->resetAfterTest(); 52 $this->setAdminUser(); 53 } 54 55 /** 56 * Test getting the event factory. 57 */ 58 public function test_get_event_factory() { 59 $factory = \core_calendar\local\event\container::get_event_factory(); 60 61 // Test that the container is returning the right type. 62 $this->assertInstanceOf(event_factory_interface::class, $factory); 63 // Test that the container is returning the right implementation. 64 $this->assertInstanceOf(event_factory::class, $factory); 65 66 // Test that getting the factory a second time returns the same instance. 67 $factory2 = \core_calendar\local\event\container::get_event_factory(); 68 $this->assertTrue($factory === $factory2); 69 } 70 71 /** 72 * Test that the event factory correctly creates instances of events. 73 * 74 * @dataProvider get_event_factory_testcases() 75 * @param \stdClass $dbrow Row from the "database". 76 */ 77 public function test_event_factory_create_instance($dbrow) { 78 $legacyevent = $this->create_event($dbrow); 79 $factory = \core_calendar\local\event\container::get_event_factory(); 80 $course = $this->getDataGenerator()->create_course(); 81 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 82 $moduleinstance = $generator->create_instance(['course' => $course->id]); 83 84 // Set some of the fake dbrow properties to match real data in the DB 85 // this is necessary as the factory hides things that modinfo doesn't 86 // know about. 87 $dbrow->id = $legacyevent->id; 88 $dbrow->courseid = $course->id; 89 $dbrow->instance = $moduleinstance->id; 90 $dbrow->modulename = 'assign'; 91 $event = $factory->create_instance($dbrow); 92 93 // Test that the factory is returning the right type. 94 $this->assertInstanceOf(event_interface::class, $event); 95 // Test that the factory is returning the right implementation. 96 $this->assertTrue($event instanceof event || $event instanceof action_event); 97 98 // Test that the event created has the correct properties. 99 $this->assertEquals($legacyevent->id, $event->get_id()); 100 $this->assertEquals($dbrow->description, $event->get_description()->get_value()); 101 $this->assertEquals($dbrow->format, $event->get_description()->get_format()); 102 $this->assertEquals($dbrow->courseid, $event->get_course()->get('id')); 103 $this->assertEquals($dbrow->location, $event->get_location()); 104 105 if ($dbrow->groupid == 0) { 106 $this->assertNull($event->get_group()); 107 } else { 108 $this->assertEquals($dbrow->groupid, $event->get_group()->get('id')); 109 } 110 111 $this->assertEquals($dbrow->userid, $event->get_user()->get('id')); 112 $this->assertEquals(null, $event->get_repeats()); 113 $this->assertEquals($dbrow->modulename, $event->get_course_module()->get('modname')); 114 $this->assertEquals($dbrow->instance, $event->get_course_module()->get('instance')); 115 $this->assertEquals($dbrow->timestart, $event->get_times()->get_start_time()->getTimestamp()); 116 $this->assertEquals($dbrow->timemodified, $event->get_times()->get_modified_time()->getTimestamp()); 117 $this->assertEquals($dbrow->timesort, $event->get_times()->get_sort_time()->getTimestamp()); 118 119 if ($dbrow->visible == 1) { 120 $this->assertTrue($event->is_visible()); 121 } else { 122 $this->assertFalse($event->is_visible()); 123 } 124 125 if (!$dbrow->subscriptionid) { 126 $this->assertNull($event->get_subscription()); 127 } else { 128 $this->assertEquals($event->get_subscription()->get('id')); 129 } 130 } 131 132 /** 133 * Test that the event factory deals with invisible modules properly as admin. 134 * 135 * @dataProvider get_event_factory_testcases() 136 * @param \stdClass $dbrow Row from the "database". 137 */ 138 public function test_event_factory_when_module_visibility_is_toggled_as_admin($dbrow) { 139 $legacyevent = $this->create_event($dbrow); 140 $factory = \core_calendar\local\event\container::get_event_factory(); 141 $course = $this->getDataGenerator()->create_course(); 142 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 143 $moduleinstance = $generator->create_instance(['course' => $course->id]); 144 145 $dbrow->id = $legacyevent->id; 146 $dbrow->courseid = $course->id; 147 $dbrow->instance = $moduleinstance->id; 148 $dbrow->modulename = 'assign'; 149 150 set_coursemodule_visible($moduleinstance->cmid, 0); 151 152 $event = $factory->create_instance($dbrow); 153 154 // Test that the factory is returning an event as the admin can see hidden course modules. 155 $this->assertInstanceOf(event_interface::class, $event); 156 } 157 158 /** 159 * Test that the event factory deals with invisible modules properly as a guest. 160 * 161 * @dataProvider get_event_factory_testcases() 162 * @param \stdClass $dbrow Row from the "database". 163 */ 164 public function test_event_factory_when_module_visibility_is_toggled_as_guest($dbrow) { 165 $legacyevent = $this->create_event($dbrow); 166 $factory = \core_calendar\local\event\container::get_event_factory(); 167 $course = $this->getDataGenerator()->create_course(); 168 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 169 $moduleinstance = $generator->create_instance(['course' => $course->id]); 170 171 $dbrow->id = $legacyevent->id; 172 $dbrow->courseid = $course->id; 173 $dbrow->instance = $moduleinstance->id; 174 $dbrow->modulename = 'assign'; 175 176 set_coursemodule_visible($moduleinstance->cmid, 0); 177 178 // Set to a user who can not view hidden course modules. 179 $this->setGuestUser(); 180 181 $event = $factory->create_instance($dbrow); 182 183 // Module is invisible to guest users so this should return null. 184 $this->assertNull($event); 185 } 186 187 /** 188 * Test that the event factory deals with invisible courses as an admin. 189 * 190 * @dataProvider get_event_factory_testcases() 191 * @param \stdClass $dbrow Row from the "database". 192 */ 193 public function test_event_factory_when_course_visibility_is_toggled_as_admin($dbrow) { 194 $legacyevent = $this->create_event($dbrow); 195 $factory = \core_calendar\local\event\container::get_event_factory(); 196 197 // Create a hidden course with an assignment. 198 $course = $this->getDataGenerator()->create_course(['visible' => 0]); 199 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 200 $moduleinstance = $generator->create_instance(['course' => $course->id]); 201 202 $dbrow->id = $legacyevent->id; 203 $dbrow->courseid = $course->id; 204 $dbrow->instance = $moduleinstance->id; 205 $dbrow->modulename = 'assign'; 206 $event = $factory->create_instance($dbrow); 207 208 // Module is still visible to admins even if the course is invisible. 209 $this->assertInstanceOf(event_interface::class, $event); 210 } 211 212 /** 213 * Test that the event factory deals with invisible courses as a student. 214 * 215 * @dataProvider get_event_factory_testcases() 216 * @param \stdClass $dbrow Row from the "database". 217 */ 218 public function test_event_factory_when_course_visibility_is_toggled_as_student($dbrow) { 219 $legacyevent = $this->create_event($dbrow); 220 $factory = \core_calendar\local\event\container::get_event_factory(); 221 222 // Create a hidden course with an assignment. 223 $course = $this->getDataGenerator()->create_course(['visible' => 0]); 224 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 225 $moduleinstance = $generator->create_instance(['course' => $course->id]); 226 227 // Enrol a student into this course. 228 $student = $this->getDataGenerator()->create_user(); 229 $this->getDataGenerator()->enrol_user($student->id, $course->id); 230 231 // Set the user to the student. 232 $this->setUser($student); 233 234 $dbrow->id = $legacyevent->id; 235 $dbrow->courseid = $course->id; 236 $dbrow->instance = $moduleinstance->id; 237 $dbrow->modulename = 'assign'; 238 $event = $factory->create_instance($dbrow); 239 240 // Module is invisible to students if the course is invisible. 241 $this->assertNull($event); 242 } 243 244 /** 245 * Test that the event factory deals with invisible categorys as an admin. 246 */ 247 public function test_event_factory_when_category_visibility_is_toggled_as_admin() { 248 // Create a hidden category. 249 $category = $this->getDataGenerator()->create_category(['visible' => 0]); 250 251 $eventdata = [ 252 'categoryid' => $category->id, 253 'eventtype' => 'category', 254 ]; 255 $legacyevent = $this->create_event($eventdata); 256 257 $dbrow = $this->get_dbrow_from_skeleton((object) $eventdata); 258 $dbrow->id = $legacyevent->id; 259 260 $factory = \core_calendar\local\event\container::get_event_factory(); 261 $event = $factory->create_instance($dbrow); 262 263 // Module is still visible to admins even if the category is invisible. 264 $this->assertInstanceOf(event_interface::class, $event); 265 } 266 267 /** 268 * Test that the event factory deals with invisible categorys as an user. 269 */ 270 public function test_event_factory_when_category_visibility_is_toggled_as_user() { 271 // Create a hidden category. 272 $category = $this->getDataGenerator()->create_category(['visible' => 0]); 273 274 $eventdata = [ 275 'categoryid' => $category->id, 276 'eventtype' => 'category', 277 ]; 278 $legacyevent = $this->create_event($eventdata); 279 280 $dbrow = $this->get_dbrow_from_skeleton((object) $eventdata); 281 $dbrow->id = $legacyevent->id; 282 283 // Use a standard user. 284 $user = $this->getDataGenerator()->create_user(); 285 286 // Set the user to the student. 287 $this->setUser($user); 288 289 $factory = \core_calendar\local\event\container::get_event_factory(); 290 $event = $factory->create_instance($dbrow); 291 292 // Module is invisible to non-privileged users. 293 $this->assertNull($event); 294 } 295 296 /** 297 * Test that the event factory deals with invisible categorys as an guest. 298 */ 299 public function test_event_factory_when_category_visibility_is_toggled_as_guest() { 300 // Create a hidden category. 301 $category = $this->getDataGenerator()->create_category(['visible' => 0]); 302 303 $eventdata = [ 304 'categoryid' => $category->id, 305 'eventtype' => 'category', 306 ]; 307 $legacyevent = $this->create_event($eventdata); 308 309 $dbrow = $this->get_dbrow_from_skeleton((object) $eventdata); 310 $dbrow->id = $legacyevent->id; 311 312 // Set the user to the student. 313 $this->setGuestUser(); 314 315 $factory = \core_calendar\local\event\container::get_event_factory(); 316 $event = $factory->create_instance($dbrow); 317 318 // Module is invisible to guests. 319 $this->assertNull($event); 320 } 321 322 /** 323 * Test that the event factory deals with completion related events properly. 324 */ 325 public function test_event_factory_with_completion_related_event() { 326 global $CFG; 327 328 $CFG->enablecompletion = true; 329 330 // Create the course we will be using. 331 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 332 333 // Add the assignment. 334 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 335 $assign = $generator->create_instance(array('course' => $course->id), array('completion' => 1)); 336 337 // Create a completion event. 338 $event = new \stdClass(); 339 $event->name = 'An event'; 340 $event->description = 'Event description'; 341 $event->location = 'Event location'; 342 $event->format = FORMAT_HTML; 343 $event->eventtype = \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED; 344 $event->userid = 1; 345 $event->modulename = 'assign'; 346 $event->instance = $assign->id; 347 $event->categoryid = 0; 348 $event->courseid = $course->id; 349 $event->groupid = 0; 350 $event->timestart = time(); 351 $event->timesort = time(); 352 $event->timemodified = time(); 353 $event->timeduration = 0; 354 $event->subscriptionid = null; 355 $event->repeatid = 0; 356 $legacyevent = $this->create_event($event); 357 358 // Update the id of the event that was created. 359 $event->id = $legacyevent->id; 360 361 // Create the factory we are going to be testing the behaviour of. 362 $factory = \core_calendar\local\event\container::get_event_factory(); 363 364 // Check that we get the correct instance. 365 $this->assertInstanceOf(event_interface::class, $factory->create_instance($event)); 366 367 // Now, disable completion. 368 $CFG->enablecompletion = false; 369 370 // The result should now be null since we have disabled completion. 371 $this->assertNull($factory->create_instance($event)); 372 } 373 374 /** 375 * Test that the event factory only returns an event if the logged in user 376 * is enrolled in the course. 377 */ 378 public function test_event_factory_unenrolled_user() { 379 $user = $this->getDataGenerator()->create_user(); 380 // Create the course we will be using. 381 $course = $this->getDataGenerator()->create_course(); 382 383 // Add the assignment. 384 $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson'); 385 $lesson = $generator->create_instance(array('course' => $course->id)); 386 387 // Create a user override event for the lesson. 388 $event = new \stdClass(); 389 $event->name = 'An event'; 390 $event->description = 'Event description'; 391 $event->location = 'Event location'; 392 $event->format = FORMAT_HTML; 393 $event->eventtype = 'close'; 394 $event->userid = $user->id; 395 $event->modulename = 'lesson'; 396 $event->instance = $lesson->id; 397 $event->categoryid = 0; 398 $event->courseid = $course->id; 399 $event->groupid = 0; 400 $event->timestart = time(); 401 $event->timesort = time(); 402 $event->timemodified = time(); 403 $event->timeduration = 0; 404 $event->subscriptionid = null; 405 $event->repeatid = 0; 406 $legacyevent = $this->create_event($event); 407 408 // Update the id of the event that was created. 409 $event->id = $legacyevent->id; 410 411 // Set the logged in user to the one we created. 412 $this->setUser($user); 413 414 // Create the factory we are going to be testing the behaviour of. 415 $factory = \core_calendar\local\event\container::get_event_factory(); 416 417 // The result should be null since the user is not enrolled in the 418 // course the event is for. 419 $this->assertNull($factory->create_instance($event)); 420 421 // Now enrol the user in the course. 422 $this->getDataGenerator()->enrol_user($user->id, $course->id); 423 424 // Check that we get the correct instance. 425 $this->assertInstanceOf(event_interface::class, $factory->create_instance($event)); 426 } 427 428 /** 429 * Test that when course module is deleted all events are also deleted. 430 */ 431 public function test_delete_module_delete_events() { 432 global $DB; 433 $user = $this->getDataGenerator()->create_user(); 434 // Create the course we will be using. 435 $course = $this->getDataGenerator()->create_course(); 436 $group = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 437 438 foreach (core_component::get_plugin_list('mod') as $modname => $unused) { 439 try { 440 $generator = $this->getDataGenerator()->get_plugin_generator('mod_'.$modname); 441 } catch (coding_exception $e) { 442 // Module generator is not implemented. 443 continue; 444 } 445 $module = $generator->create_instance(['course' => $course->id]); 446 447 // Create bunch of events of different type (user override, group override, module event). 448 $this->create_event(['userid' => $user->id, 'modulename' => $modname, 'instance' => $module->id]); 449 $this->create_event(['groupid' => $group->id, 'modulename' => $modname, 'instance' => $module->id]); 450 $this->create_event(['modulename' => $modname, 'instance' => $module->id]); 451 $this->create_event(['modulename' => $modname, 'instance' => $module->id, 'courseid' => $course->id]); 452 453 // Delete module and make sure all events are deleted. 454 course_delete_module($module->cmid); 455 $this->assertEmpty($DB->get_record('event', ['modulename' => $modname, 'instance' => $module->id])); 456 } 457 } 458 459 /** 460 * Test getting the event mapper. 461 */ 462 public function test_get_event_mapper() { 463 $mapper = \core_calendar\local\event\container::get_event_mapper(); 464 465 $this->assertInstanceOf(event_mapper_interface::class, $mapper); 466 $this->assertInstanceOf(event_mapper::class, $mapper); 467 468 $mapper2 = \core_calendar\local\event\container::get_event_mapper(); 469 470 $this->assertTrue($mapper === $mapper2); 471 } 472 473 /** 474 * Test cases for the get event factory test. 475 */ 476 public function get_event_factory_testcases() { 477 return [ 478 'Data set 1' => [ 479 'dbrow' => (object)[ 480 'name' => 'Test event', 481 'description' => 'Hello', 482 'format' => 1, 483 'categoryid' => 0, 484 'courseid' => 1, 485 'groupid' => 0, 486 'userid' => 1, 487 'repeatid' => 0, 488 'modulename' => 'assign', 489 'instance' => 2, 490 'eventtype' => 'due', 491 'timestart' => 1486396800, 492 'timeduration' => 0, 493 'timesort' => 1486396800, 494 'visible' => 1, 495 'timemodified' => 1485793098, 496 'subscriptionid' => null, 497 'location' => 'Test location', 498 ] 499 ], 500 501 'Data set 2' => [ 502 'dbrow' => (object)[ 503 'name' => 'Test event', 504 'description' => 'Hello', 505 'format' => 1, 506 'categoryid' => 0, 507 'courseid' => 1, 508 'groupid' => 1, 509 'userid' => 1, 510 'repeatid' => 0, 511 'modulename' => 'assign', 512 'instance' => 2, 513 'eventtype' => 'due', 514 'timestart' => 1486396800, 515 'timeduration' => 0, 516 'timesort' => 1486396800, 517 'visible' => 1, 518 'timemodified' => 1485793098, 519 'subscriptionid' => null, 520 'location' => 'Test location', 521 ] 522 ] 523 ]; 524 } 525 526 /** 527 * Helper function to create calendar events using the old code. 528 * 529 * @param array $properties A list of calendar event properties to set 530 * @return calendar_event|bool 531 */ 532 protected function create_event($properties = []) { 533 $record = new \stdClass(); 534 $record->name = 'event name'; 535 $record->eventtype = 'site'; 536 $record->timestart = time(); 537 $record->timeduration = 0; 538 $record->timesort = 0; 539 $record->type = 1; 540 $record->courseid = 0; 541 $record->categoryid = 0; 542 543 foreach ($properties as $name => $value) { 544 $record->$name = $value; 545 } 546 547 $event = new calendar_event($record); 548 return $event->create($record, false); 549 } 550 551 /** 552 * Pad out a basic DB row with basic information. 553 * 554 * @param \stdClass $skeleton the current skeleton 555 * @return \stdClass 556 */ 557 protected function get_dbrow_from_skeleton($skeleton) { 558 $dbrow = (object) [ 559 'name' => 'Name', 560 'description' => 'Description', 561 'format' => 1, 562 'categoryid' => 0, 563 'courseid' => 0, 564 'groupid' => 0, 565 'userid' => 0, 566 'repeatid' => 0, 567 'modulename' => '', 568 'instance' => 0, 569 'eventtype' => 'user', 570 'timestart' => 1486396800, 571 'timeduration' => 0, 572 'timesort' => 1486396800, 573 'visible' => 1, 574 'timemodified' => 1485793098, 575 'subscriptionid' => null, 576 'location' => 'Test location', 577 ]; 578 579 foreach ((array) $skeleton as $key => $value) { 580 $dbrow->$key = $value; 581 } 582 583 return $dbrow; 584 } 585 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body