Differences Between: [Versions 310 and 402] [Versions 39 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Glossary lib tests. 19 * 20 * @package mod_glossary 21 * @copyright 2015 Frédéric Massart - FMCorz.net 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace mod_glossary; 25 26 defined('MOODLE_INTERNAL') || die(); 27 28 global $CFG; 29 require_once($CFG->dirroot . '/mod/glossary/lib.php'); 30 require_once($CFG->dirroot . '/mod/glossary/locallib.php'); 31 32 /** 33 * Glossary lib testcase. 34 * 35 * @package mod_glossary 36 * @copyright 2015 Frédéric Massart - FMCorz.net 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class lib_test extends \advanced_testcase { 40 41 public function test_glossary_view() { 42 global $CFG; 43 $origcompletion = $CFG->enablecompletion; 44 $CFG->enablecompletion = true; 45 $this->resetAfterTest(true); 46 47 // Generate all the things. 48 $c1 = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 49 $g1 = $this->getDataGenerator()->create_module('glossary', array( 50 'course' => $c1->id, 51 'completion' => COMPLETION_TRACKING_AUTOMATIC, 52 'completionview' => 1 53 )); 54 $g2 = $this->getDataGenerator()->create_module('glossary', array( 55 'course' => $c1->id, 56 'completion' => COMPLETION_TRACKING_AUTOMATIC, 57 'completionview' => 1 58 )); 59 $u1 = $this->getDataGenerator()->create_user(); 60 $this->getDataGenerator()->enrol_user($u1->id, $c1->id); 61 $modinfo = \course_modinfo::instance($c1->id); 62 $cm1 = $modinfo->get_cm($g1->cmid); 63 $cm2 = $modinfo->get_cm($g2->cmid); 64 $ctx1 = $cm1->context; 65 $completion = new \completion_info($c1); 66 67 $this->setUser($u1); 68 69 // Confirm what we've set up. 70 $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed); 71 $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate); 72 $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed); 73 $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate); 74 75 // Simulate the view call. 76 $sink = $this->redirectEvents(); 77 glossary_view($g1, $c1, $cm1, $ctx1, 'letter'); 78 $events = $sink->get_events(); 79 80 // Assertions. 81 $this->assertCount(3, $events); 82 $this->assertEquals('\core\event\course_module_completion_updated', $events[0]->eventname); 83 $this->assertEquals('\core\event\course_module_completion_updated', $events[1]->eventname); 84 $this->assertEquals('\mod_glossary\event\course_module_viewed', $events[2]->eventname); 85 $this->assertEquals($g1->id, $events[2]->objectid); 86 $this->assertEquals('letter', $events[2]->other['mode']); 87 $this->assertEquals(COMPLETION_VIEWED, $completion->get_data($cm1, false, $u1->id)->viewed); 88 $this->assertEquals(COMPLETION_COMPLETE, $completion->get_data($cm1, false, $u1->id)->completionstate); 89 $this->assertEquals(COMPLETION_NOT_VIEWED, $completion->get_data($cm2, false, $u1->id)->viewed); 90 $this->assertEquals(COMPLETION_INCOMPLETE, $completion->get_data($cm2, false, $u1->id)->completionstate); 91 92 // Tear down. 93 $sink->close(); 94 $CFG->enablecompletion = $origcompletion; 95 } 96 97 public function test_glossary_entry_view() { 98 $this->resetAfterTest(true); 99 100 // Generate all the things. 101 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 102 $c1 = $this->getDataGenerator()->create_course(); 103 $g1 = $this->getDataGenerator()->create_module('glossary', array('course' => $c1->id)); 104 $e1 = $gg->create_content($g1); 105 $u1 = $this->getDataGenerator()->create_user(); 106 $ctx = \context_module::instance($g1->cmid); 107 $this->getDataGenerator()->enrol_user($u1->id, $c1->id); 108 109 // Assertions. 110 $sink = $this->redirectEvents(); 111 glossary_entry_view($e1, $ctx); 112 $events = $sink->get_events(); 113 $this->assertCount(1, $events); 114 $this->assertEquals('\mod_glossary\event\entry_viewed', $events[0]->eventname); 115 $this->assertEquals($e1->id, $events[0]->objectid); 116 $sink->close(); 117 } 118 119 public function test_glossary_core_calendar_provide_event_action() { 120 $this->resetAfterTest(); 121 $this->setAdminUser(); 122 123 // Create the activity. 124 $course = $this->getDataGenerator()->create_course(); 125 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 126 127 // Create a calendar event. 128 $event = $this->create_action_event($course->id, $glossary->id, 129 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 130 131 // Create an action factory. 132 $factory = new \core_calendar\action_factory(); 133 134 // Decorate action event. 135 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory); 136 137 // Confirm the event was decorated. 138 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 139 $this->assertEquals(get_string('view'), $actionevent->get_name()); 140 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 141 $this->assertEquals(1, $actionevent->get_item_count()); 142 $this->assertTrue($actionevent->is_actionable()); 143 } 144 145 public function test_glossary_core_calendar_provide_event_action_as_non_user() { 146 global $CFG; 147 148 $this->resetAfterTest(); 149 $this->setAdminUser(); 150 151 // Create the activity. 152 $course = $this->getDataGenerator()->create_course(); 153 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 154 155 // Create a calendar event. 156 $event = $this->create_action_event($course->id, $glossary->id, 157 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 158 159 // Now log out. 160 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 161 $this->setUser(); 162 163 // Create an action factory. 164 $factory = new \core_calendar\action_factory(); 165 166 // Decorate action event for the student. 167 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory); 168 169 // Confirm the event is not shown at all. 170 $this->assertNull($actionevent); 171 } 172 173 public function test_glossary_core_calendar_provide_event_action_for_user() { 174 global $CFG; 175 176 $this->resetAfterTest(); 177 $this->setAdminUser(); 178 179 // Create a course. 180 $course = $this->getDataGenerator()->create_course(); 181 182 // Create a student. 183 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 184 185 // Create the activity. 186 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 187 188 // Create a calendar event. 189 $event = $this->create_action_event($course->id, $glossary->id, 190 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 191 192 // Now log out. 193 $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. 194 $this->setUser(); 195 196 // Create an action factory. 197 $factory = new \core_calendar\action_factory(); 198 199 // Decorate action event for the student. 200 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id); 201 202 // Confirm the event was decorated. 203 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); 204 $this->assertEquals(get_string('view'), $actionevent->get_name()); 205 $this->assertInstanceOf('moodle_url', $actionevent->get_url()); 206 $this->assertEquals(1, $actionevent->get_item_count()); 207 $this->assertTrue($actionevent->is_actionable()); 208 } 209 210 public function test_glossary_core_calendar_provide_event_action_in_hidden_section() { 211 $this->resetAfterTest(); 212 $this->setAdminUser(); 213 214 // Create a course. 215 $course = $this->getDataGenerator()->create_course(); 216 217 // Create a student. 218 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 219 220 // Create the activity. 221 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 222 223 // Create a calendar event. 224 $event = $this->create_action_event($course->id, $glossary->id, 225 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 226 227 // Set sections 0 as hidden. 228 set_section_visible($course->id, 0, 0); 229 230 // Create an action factory. 231 $factory = new \core_calendar\action_factory(); 232 233 // Decorate action event for the student. 234 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id); 235 236 // Confirm the event is not shown at all. 237 $this->assertNull($actionevent); 238 } 239 240 public function test_glossary_core_calendar_provide_event_action_already_completed() { 241 global $CFG; 242 243 $this->resetAfterTest(); 244 $this->setAdminUser(); 245 246 $CFG->enablecompletion = 1; 247 248 // Create the activity. 249 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 250 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id), 251 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 252 253 // Get some additional data. 254 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 255 256 // Create a calendar event. 257 $event = $this->create_action_event($course->id, $glossary->id, 258 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 259 260 // Mark the activity as completed. 261 $completion = new \completion_info($course); 262 $completion->set_module_viewed($cm); 263 264 // Create an action factory. 265 $factory = new \core_calendar\action_factory(); 266 267 // Decorate action event. 268 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory); 269 270 // Ensure result was null. 271 $this->assertNull($actionevent); 272 } 273 274 public function test_glossary_core_calendar_provide_event_action_already_completed_for_user() { 275 global $CFG; 276 277 $this->resetAfterTest(); 278 $this->setAdminUser(); 279 280 $CFG->enablecompletion = 1; 281 282 // Create a course. 283 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); 284 285 // Create a student. 286 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 287 288 // Create the activity. 289 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id), 290 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); 291 292 // Get some additional data. 293 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 294 295 // Create a calendar event. 296 $event = $this->create_action_event($course->id, $glossary->id, 297 \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); 298 299 // Mark the activity as completed for the user. 300 $completion = new \completion_info($course); 301 $completion->set_module_viewed($cm, $student->id); 302 303 // Create an action factory. 304 $factory = new \core_calendar\action_factory(); 305 306 // Decorate action event. 307 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id); 308 309 // Ensure result was null. 310 $this->assertNull($actionevent); 311 } 312 313 /** 314 * Creates an action event. 315 * 316 * @param int $courseid The course id. 317 * @param int $instanceid The instance id. 318 * @param string $eventtype The event type. 319 * @return bool|calendar_event 320 */ 321 private function create_action_event($courseid, $instanceid, $eventtype) { 322 $event = new \stdClass(); 323 $event->name = 'Calendar event'; 324 $event->modulename = 'glossary'; 325 $event->courseid = $courseid; 326 $event->instance = $instanceid; 327 $event->type = CALENDAR_EVENT_TYPE_ACTION; 328 $event->eventtype = $eventtype; 329 $event->timestart = time(); 330 331 return \calendar_event::create($event); 332 } 333 334 /** 335 * Test the callback responsible for returning the completion rule descriptions. 336 * This function should work given either an instance of the module (cm_info), such as when checking the active rules, 337 * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type. 338 */ 339 public function test_mod_glossary_completion_get_active_rule_descriptions() { 340 $this->resetAfterTest(); 341 $this->setAdminUser(); 342 343 // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't. 344 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]); 345 $glossary1 = $this->getDataGenerator()->create_module('glossary', [ 346 'course' => $course->id, 347 'completion' => 2, 348 'completionentries' => 3 349 ]); 350 $glossary2 = $this->getDataGenerator()->create_module('glossary', [ 351 'course' => $course->id, 352 'completion' => 2, 353 'completionentries' => 0 354 ]); 355 $cm1 = \cm_info::create(get_coursemodule_from_instance('glossary', $glossary1->id)); 356 $cm2 = \cm_info::create(get_coursemodule_from_instance('glossary', $glossary2->id)); 357 358 // Data for the stdClass input type. 359 // This type of input would occur when checking the default completion rules for an activity type, where we don't have 360 // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info. 361 $moddefaults = new \stdClass(); 362 $moddefaults->customdata = ['customcompletionrules' => ['completionentries' => 3]]; 363 $moddefaults->completion = 2; 364 365 $activeruledescriptions = [get_string('completionentriesdesc', 'glossary', $glossary1->completionentries)]; 366 $this->assertEquals(mod_glossary_get_completion_active_rule_descriptions($cm1), $activeruledescriptions); 367 $this->assertEquals(mod_glossary_get_completion_active_rule_descriptions($cm2), []); 368 $this->assertEquals(mod_glossary_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions); 369 $this->assertEquals(mod_glossary_get_completion_active_rule_descriptions(new \stdClass()), []); 370 } 371 372 public function test_mod_glossary_get_tagged_entries() { 373 global $DB; 374 375 $this->resetAfterTest(); 376 $this->setAdminUser(); 377 378 // Setup test data. 379 $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 380 $course3 = $this->getDataGenerator()->create_course(); 381 $course2 = $this->getDataGenerator()->create_course(); 382 $course1 = $this->getDataGenerator()->create_course(); 383 384 // Create and enrol a student. 385 $student = self::getDataGenerator()->create_user(); 386 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 387 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); 388 $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); 389 390 // Create glossaries and entries. 391 $glossary1 = $this->getDataGenerator()->create_module('glossary', array('course' => $course1->id)); 392 $glossary2 = $this->getDataGenerator()->create_module('glossary', array('course' => $course2->id)); 393 $glossary3 = $this->getDataGenerator()->create_module('glossary', array('course' => $course3->id)); 394 $entry11 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats', 'Dogs'))); 395 $entry12 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats', 'mice'))); 396 $entry13 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats'))); 397 $entry14 = $glossarygenerator->create_content($glossary1); 398 $entry15 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats'))); 399 $entry16 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats'), 'approved' => false)); 400 $entry17 = $glossarygenerator->create_content($glossary1, array('tags' => array('Cats'), 'approved' => false, 'userid' => $student->id)); 401 $entry21 = $glossarygenerator->create_content($glossary2, array('tags' => array('Cats'))); 402 $entry22 = $glossarygenerator->create_content($glossary2, array('tags' => array('Cats', 'Dogs'))); 403 $entry23 = $glossarygenerator->create_content($glossary2, array('tags' => array('mice', 'Cats'))); 404 $entry31 = $glossarygenerator->create_content($glossary3, array('tags' => array('mice', 'Cats'))); 405 406 $tag = \core_tag_tag::get_by_name(0, 'Cats'); 407 408 // Admin can see everything. 409 // Get first page of tagged entries (first 5 entries). 410 $res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false, 411 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */0); 412 $this->assertMatchesRegularExpression('/'.$entry11->concept.'</', $res->content); 413 $this->assertMatchesRegularExpression('/'.$entry12->concept.'</', $res->content); 414 $this->assertMatchesRegularExpression('/'.$entry13->concept.'</', $res->content); 415 $this->assertDoesNotMatchRegularExpression('/'.$entry14->concept.'</', $res->content); 416 $this->assertMatchesRegularExpression('/'.$entry15->concept.'</', $res->content); 417 $this->assertMatchesRegularExpression('/'.$entry16->concept.'</', $res->content); 418 $this->assertDoesNotMatchRegularExpression('/'.$entry17->concept.'</', $res->content); 419 $this->assertDoesNotMatchRegularExpression('/'.$entry21->concept.'</', $res->content); 420 $this->assertDoesNotMatchRegularExpression('/'.$entry22->concept.'</', $res->content); 421 $this->assertDoesNotMatchRegularExpression('/'.$entry23->concept.'</', $res->content); 422 $this->assertDoesNotMatchRegularExpression('/'.$entry31->concept.'</', $res->content); 423 $this->assertEmpty($res->prevpageurl); 424 $this->assertNotEmpty($res->nextpageurl); 425 // Get second page of tagged entries (second 5 entries). 426 $res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false, 427 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */1); 428 $this->assertDoesNotMatchRegularExpression('/'.$entry11->concept.'</', $res->content); 429 $this->assertDoesNotMatchRegularExpression('/'.$entry12->concept.'</', $res->content); 430 $this->assertDoesNotMatchRegularExpression('/'.$entry13->concept.'</', $res->content); 431 $this->assertDoesNotMatchRegularExpression('/'.$entry14->concept.'</', $res->content); 432 $this->assertDoesNotMatchRegularExpression('/'.$entry15->concept.'</', $res->content); 433 $this->assertDoesNotMatchRegularExpression('/'.$entry16->concept.'</', $res->content); 434 $this->assertMatchesRegularExpression('/'.$entry17->concept.'</', $res->content); 435 $this->assertMatchesRegularExpression('/'.$entry21->concept.'</', $res->content); 436 $this->assertMatchesRegularExpression('/'.$entry22->concept.'</', $res->content); 437 $this->assertMatchesRegularExpression('/'.$entry23->concept.'</', $res->content); 438 $this->assertMatchesRegularExpression('/'.$entry31->concept.'</', $res->content); 439 $this->assertNotEmpty($res->prevpageurl); 440 $this->assertEmpty($res->nextpageurl); 441 442 $this->setUser($student); 443 \core_tag_index_builder::reset_caches(); 444 445 // User can not see entries in course 3 because he is not enrolled. 446 $res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false, 447 /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$entry = */1); 448 $this->assertMatchesRegularExpression('/'.$entry22->concept.'/', $res->content); 449 $this->assertMatchesRegularExpression('/'.$entry23->concept.'/', $res->content); 450 $this->assertDoesNotMatchRegularExpression('/'.$entry31->concept.'/', $res->content); 451 452 // User can search glossary entries inside a course. 453 $coursecontext = \context_course::instance($course1->id); 454 $res = mod_glossary_get_tagged_entries($tag, /*$exclusivemode = */false, 455 /*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$entry = */0); 456 $this->assertMatchesRegularExpression('/'.$entry11->concept.'/', $res->content); 457 $this->assertMatchesRegularExpression('/'.$entry12->concept.'/', $res->content); 458 $this->assertMatchesRegularExpression('/'.$entry13->concept.'/', $res->content); 459 $this->assertDoesNotMatchRegularExpression('/'.$entry14->concept.'/', $res->content); 460 $this->assertMatchesRegularExpression('/'.$entry15->concept.'/', $res->content); 461 $this->assertDoesNotMatchRegularExpression('/'.$entry21->concept.'/', $res->content); 462 $this->assertDoesNotMatchRegularExpression('/'.$entry22->concept.'/', $res->content); 463 $this->assertDoesNotMatchRegularExpression('/'.$entry23->concept.'/', $res->content); 464 $this->assertEmpty($res->nextpageurl); 465 466 // User cannot see unapproved entries unless he is an author. 467 $this->assertDoesNotMatchRegularExpression('/'.$entry16->concept.'/', $res->content); 468 $this->assertMatchesRegularExpression('/'.$entry17->concept.'/', $res->content); 469 } 470 471 public function test_glossary_get_entries_search() { 472 $this->resetAfterTest(); 473 $this->setAdminUser(); 474 // Turn on glossary autolinking (usedynalink). 475 set_config('glossary_linkentries', 1); 476 $glossarygenerator = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 477 $course = $this->getDataGenerator()->create_course(); 478 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 479 // Note this entry is not case sensitive by default (casesensitive = 0). 480 $entry = $glossarygenerator->create_content($glossary); 481 // Check that a search for the concept return the entry. 482 $concept = $entry->concept; 483 $search = glossary_get_entries_search($concept, $course->id); 484 $this->assertCount(1, $search); 485 $foundentry = array_shift($search); 486 $this->assertEquals($foundentry->concept, $entry->concept); 487 // Now try the same search but with a lowercase term. 488 $concept = strtolower($entry->concept); 489 $search = glossary_get_entries_search($concept, $course->id); 490 $this->assertCount(1, $search); 491 $foundentry = array_shift($search); 492 $this->assertEquals($foundentry->concept, $entry->concept); 493 494 // Make an entry that is case sensitive (casesensitive = 1). 495 set_config('glossary_casesensitive', 1); 496 $entry = $glossarygenerator->create_content($glossary); 497 $concept = $entry->concept; 498 $search = glossary_get_entries_search($concept, $course->id); 499 $this->assertCount(1, $search); 500 $foundentry = array_shift($search); 501 $this->assertEquals($foundentry->concept, $entry->concept); 502 // Now try the same search but with a lowercase term. 503 $concept = strtolower($entry->concept); 504 $search = glossary_get_entries_search($concept, $course->id); 505 $this->assertCount(0, $search); 506 } 507 508 public function test_mod_glossary_can_delete_entry_users() { 509 $this->resetAfterTest(); 510 511 // Create required data. 512 $course = $this->getDataGenerator()->create_course(); 513 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 514 $anotherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student'); 515 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 516 $glossary = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id]); 517 518 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 519 $this->setUser($student); 520 $entry = $gg->create_content($glossary); 521 $context = \context_module::instance($glossary->cmid); 522 523 // Test student can delete. 524 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context)); 525 526 // Test teacher can delete. 527 $this->setUser($teacher); 528 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context)); 529 530 // Test admin can delete. 531 $this->setAdminUser(); 532 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context)); 533 534 // Test a different student is not able to delete. 535 $this->setUser($anotherstudent); 536 $this->assertFalse(mod_glossary_can_delete_entry($entry, $glossary, $context)); 537 538 // Test exception. 539 $this->expectExceptionMessage(get_string('nopermissiontodelentry', 'error')); 540 mod_glossary_can_delete_entry($entry, $glossary, $context, false); 541 } 542 543 public function test_mod_glossary_can_delete_entry_edit_period() { 544 global $CFG; 545 $this->resetAfterTest(); 546 547 // Create required data. 548 $course = $this->getDataGenerator()->create_course(); 549 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 550 $glossary = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id, 'editalways' => 1]); 551 552 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 553 $this->setUser($student); 554 $entry = $gg->create_content($glossary); 555 $context = \context_module::instance($glossary->cmid); 556 557 // Test student can always delete when edit always is set to 1. 558 $entry->timecreated = time() - 2 * $CFG->maxeditingtime; 559 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context)); 560 561 // Test student cannot delete old entries when edit always is set to 0. 562 $glossary->editalways = 0; 563 $this->assertFalse(mod_glossary_can_delete_entry($entry, $glossary, $context)); 564 565 // Test student can delete recent entries when edit always is set to 0. 566 $entry->timecreated = time(); 567 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context)); 568 569 // Check exception. 570 $entry->timecreated = time() - 2 * $CFG->maxeditingtime; 571 $this->expectExceptionMessage(get_string('errdeltimeexpired', 'glossary')); 572 mod_glossary_can_delete_entry($entry, $glossary, $context, false); 573 } 574 575 public function test_mod_glossary_delete_entry() { 576 global $DB, $CFG; 577 $this->resetAfterTest(); 578 require_once($CFG->dirroot . '/rating/lib.php'); 579 580 // Create required data. 581 $course = $this->getDataGenerator()->create_course(); 582 $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 583 $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); 584 585 $record = new \stdClass(); 586 $record->course = $course->id; 587 $record->assessed = RATING_AGGREGATE_AVERAGE; 588 $scale = $this->getDataGenerator()->create_scale(['scale' => 'A,B,C,D']); 589 $record->scale = "-$scale->id"; 590 $glossary = $this->getDataGenerator()->create_module('glossary', $record); 591 $context = \context_module::instance($glossary->cmid); 592 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 593 594 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 595 $this->setUser($student1); 596 597 // Create entry with tags and rating. 598 $entry = $gg->create_content( 599 $glossary, 600 ['approved' => 1, 'userid' => $student1->id, 'tags' => ['Cats', 'Dogs']], 601 ['alias1', 'alias2'] 602 ); 603 604 // Rate the entry as user2. 605 $rating1 = new \stdClass(); 606 $rating1->contextid = $context->id; 607 $rating1->component = 'mod_glossary'; 608 $rating1->ratingarea = 'entry'; 609 $rating1->itemid = $entry->id; 610 $rating1->rating = 1; // 1 is A. 611 $rating1->scaleid = "-$scale->id"; 612 $rating1->userid = $student2->id; 613 $rating1->timecreated = time(); 614 $rating1->timemodified = time(); 615 $rating1->id = $DB->insert_record('rating', $rating1); 616 617 $sink = $this->redirectEvents(); 618 mod_glossary_delete_entry(fullclone($entry), $glossary, $cm, $context, $course); 619 $events = $sink->get_events(); 620 $event = array_pop($events); 621 622 // Check events. 623 $this->assertEquals('\mod_glossary\event\entry_deleted', $event->eventname); 624 $this->assertEquals($entry->id, $event->objectid); 625 $sink->close(); 626 627 // No entry, no alias, no ratings, no tags. 628 $this->assertEquals(0, $DB->count_records('glossary_entries', ['id' => $entry->id])); 629 $this->assertEquals(0, $DB->count_records('glossary_alias', ['entryid' => $entry->id])); 630 $this->assertEquals(0, $DB->count_records('rating', ['component' => 'mod_glossary', 'itemid' => $entry->id])); 631 $this->assertEmpty(\core_tag_tag::get_by_name(0, 'Cats')); 632 } 633 634 public function test_mod_glossary_delete_entry_imported() { 635 global $DB; 636 $this->resetAfterTest(); 637 638 // Create required data. 639 $course = $this->getDataGenerator()->create_course(); 640 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 641 642 $glossary1 = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id]); 643 $glossary2 = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id]); 644 645 $context = \context_module::instance($glossary2->cmid); 646 $cm = get_coursemodule_from_instance('glossary', $glossary2->id); 647 648 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 649 $this->setUser($student); 650 651 $entry1 = $gg->create_content($glossary1); 652 $entry2 = $gg->create_content( 653 $glossary2, 654 ['approved' => 1, 'userid' => $student->id, 'sourceglossaryid' => $glossary1->id, 'tags' => ['Cats', 'Dogs']] 655 ); 656 657 $sink = $this->redirectEvents(); 658 mod_glossary_delete_entry(fullclone($entry2), $glossary2, $cm, $context, $course); 659 $events = $sink->get_events(); 660 $event = array_pop($events); 661 662 // Check events. 663 $this->assertEquals('\mod_glossary\event\entry_deleted', $event->eventname); 664 $this->assertEquals($entry2->id, $event->objectid); 665 $sink->close(); 666 667 // Check source. 668 $this->assertEquals(0, $DB->get_field('glossary_entries', 'sourceglossaryid', ['id' => $entry2->id])); 669 $this->assertEquals($glossary1->id, $DB->get_field('glossary_entries', 'glossaryid', ['id' => $entry2->id])); 670 671 // Tags. 672 $this->assertEmpty(\core_tag_tag::get_by_name(0, 'Cats')); 673 } 674 675 public function test_mod_glossary_can_update_entry_users() { 676 $this->resetAfterTest(); 677 678 // Create required data. 679 $course = $this->getDataGenerator()->create_course(); 680 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 681 $anotherstudent = $this->getDataGenerator()->create_and_enrol($course, 'student'); 682 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); 683 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id)); 684 685 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 686 $this->setUser($student); 687 $entry = $gg->create_content($glossary); 688 $context = \context_module::instance($glossary->cmid); 689 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 690 691 // Test student can update. 692 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 693 694 // Test teacher can update. 695 $this->setUser($teacher); 696 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 697 698 // Test admin can update. 699 $this->setAdminUser(); 700 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 701 702 // Test a different student is not able to update. 703 $this->setUser($anotherstudent); 704 $this->assertFalse(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 705 706 // Test exception. 707 $this->expectExceptionMessage(get_string('errcannoteditothers', 'glossary')); 708 mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false); 709 } 710 711 public function test_mod_glossary_can_update_entry_edit_period() { 712 global $CFG; 713 $this->resetAfterTest(); 714 715 // Create required data. 716 $course = $this->getDataGenerator()->create_course(); 717 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 718 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id, 'editalways' => 1)); 719 720 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 721 $this->setUser($student); 722 $entry = $gg->create_content($glossary); 723 $context = \context_module::instance($glossary->cmid); 724 $cm = get_coursemodule_from_instance('glossary', $glossary->id); 725 726 // Test student can always update when edit always is set to 1. 727 $entry->timecreated = time() - 2 * $CFG->maxeditingtime; 728 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 729 730 // Test student cannot update old entries when edit always is set to 0. 731 $glossary->editalways = 0; 732 $this->assertFalse(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 733 734 // Test student can update recent entries when edit always is set to 0. 735 $entry->timecreated = time(); 736 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm)); 737 738 // Check exception. 739 $entry->timecreated = time() - 2 * $CFG->maxeditingtime; 740 $this->expectExceptionMessage(get_string('erredittimeexpired', 'glossary')); 741 mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false); 742 } 743 744 public function test_prepare_entry_for_edition() { 745 global $USER; 746 $this->resetAfterTest(true); 747 748 $course = $this->getDataGenerator()->create_course(); 749 $glossary = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id]); 750 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary'); 751 752 $this->setAdminUser(); 753 $aliases = ['alias1', 'alias2']; 754 $entry = $gg->create_content( 755 $glossary, 756 ['approved' => 1, 'userid' => $USER->id], 757 $aliases 758 ); 759 760 $cat1 = $gg->create_category($glossary, [], [$entry]); 761 $gg->create_category($glossary); 762 763 $entry = mod_glossary_prepare_entry_for_edition($entry); 764 $this->assertCount(1, $entry->categories); 765 $this->assertEquals($cat1->id, $entry->categories[0]); 766 $returnedaliases = array_values(explode("\n", trim($entry->aliases))); 767 sort($returnedaliases); 768 $this->assertEquals($aliases, $returnedaliases); 769 } 770 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body