2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
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
24 namespace mod_glossary
;
26 defined('MOODLE_INTERNAL') ||
die();
29 require_once($CFG->dirroot
. '/mod/glossary/lib.php');
30 require_once($CFG->dirroot
. '/mod/glossary/locallib.php');
33 * Glossary lib testcase.
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
39 class lib_test
extends \advanced_testcase
{
41 public function test_glossary_view() {
43 $origcompletion = $CFG->enablecompletion
;
44 $CFG->enablecompletion
= true;
45 $this->resetAfterTest(true);
47 // Generate all the things.
48 $c1 = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
49 $g1 = $this->getDataGenerator()->create_module('glossary', array(
51 'completion' => COMPLETION_TRACKING_AUTOMATIC
,
54 $g2 = $this->getDataGenerator()->create_module('glossary', array(
56 'completion' => COMPLETION_TRACKING_AUTOMATIC
,
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);
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
);
75 // Simulate the view call.
76 $sink = $this->redirectEvents();
77 glossary_view($g1, $c1, $cm1, $ctx1, 'letter');
78 $events = $sink->get_events();
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
);
94 $CFG->enablecompletion
= $origcompletion;
97 public function test_glossary_entry_view() {
98 $this->resetAfterTest(true);
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
);
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
);
119 public function test_glossary_core_calendar_provide_event_action() {
120 $this->resetAfterTest();
121 $this->setAdminUser();
123 // Create the activity.
124 $course = $this->getDataGenerator()->create_course();
125 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id
));
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
);
131 // Create an action factory.
132 $factory = new \core_calendar\action_factory
();
134 // Decorate action event.
135 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory);
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());
145 public function test_glossary_core_calendar_provide_event_action_as_non_user() {
148 $this->resetAfterTest();
149 $this->setAdminUser();
151 // Create the activity.
152 $course = $this->getDataGenerator()->create_course();
153 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id
));
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
);
160 $CFG->forcelogin
= true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
163 // Create an action factory.
164 $factory = new \core_calendar\action_factory
();
166 // Decorate action event for the student.
167 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory);
169 // Confirm the event is not shown at all.
170 $this->assertNull($actionevent);
173 public function test_glossary_core_calendar_provide_event_action_for_user() {
176 $this->resetAfterTest();
177 $this->setAdminUser();
180 $course = $this->getDataGenerator()->create_course();
183 $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
185 // Create the activity.
186 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id
));
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
);
193 $CFG->forcelogin
= true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
196 // Create an action factory.
197 $factory = new \core_calendar\action_factory
();
199 // Decorate action event for the student.
200 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id
);
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());
210 public function test_glossary_core_calendar_provide_event_action_in_hidden_section() {
211 $this->resetAfterTest();
212 $this->setAdminUser();
215 $course = $this->getDataGenerator()->create_course();
218 $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
220 // Create the activity.
221 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id
));
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
);
227 // Set sections 0 as hidden.
228 set_section_visible($course->id
, 0, 0);
230 // Create an action factory.
231 $factory = new \core_calendar\action_factory
();
233 // Decorate action event for the student.
234 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id
);
236 // Confirm the event is not shown at all.
237 $this->assertNull($actionevent);
240 public function test_glossary_core_calendar_provide_event_action_already_completed() {
243 $this->resetAfterTest();
244 $this->setAdminUser();
246 $CFG->enablecompletion
= 1;
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
));
253 // Get some additional data.
254 $cm = get_coursemodule_from_instance('glossary', $glossary->id
);
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
);
260 // Mark the activity as completed.
261 $completion = new \
completion_info($course);
262 $completion->set_module_viewed($cm);
264 // Create an action factory.
265 $factory = new \core_calendar\action_factory
();
267 // Decorate action event.
268 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory);
270 // Ensure result was null.
271 $this->assertNull($actionevent);
274 public function test_glossary_core_calendar_provide_event_action_already_completed_for_user() {
277 $this->resetAfterTest();
278 $this->setAdminUser();
280 $CFG->enablecompletion
= 1;
283 $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
286 $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
288 // Create the activity.
289 $glossary = $this->getDataGenerator()->create_module('glossary', array('course' => $course->id
),
290 array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS
));
292 // Get some additional data.
293 $cm = get_coursemodule_from_instance('glossary', $glossary->id
);
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
);
299 // Mark the activity as completed for the user.
300 $completion = new \
completion_info($course);
301 $completion->set_module_viewed($cm, $student->id
);
303 // Create an action factory.
304 $factory = new \core_calendar\action_factory
();
306 // Decorate action event.
307 $actionevent = mod_glossary_core_calendar_provide_event_action($event, $factory, $student->id
);
309 // Ensure result was null.
310 $this->assertNull($actionevent);
314 * Creates an action event.
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
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();
331 return \calendar_event
::create($event);
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.
339 public function test_mod_glossary_completion_get_active_rule_descriptions() {
340 $this->resetAfterTest();
341 $this->setAdminUser();
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
,
348 'completionentries' => 3
350 $glossary2 = $this->getDataGenerator()->create_module('glossary', [
351 'course' => $course->id
,
353 'completionentries' => 0
355 $cm1 = \cm_info
::create(get_coursemodule_from_instance('glossary', $glossary1->id
));
356 $cm2 = \cm_info
::create(get_coursemodule_from_instance('glossary', $glossary2->id
));
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;
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()), []);
372 public function test_mod_glossary_get_tagged_entries() {
375 $this->resetAfterTest();
376 $this->setAdminUser();
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();
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');
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')));
406 $tag = \core_tag_tag
::get_by_name(0, 'Cats');
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
);
442 $this->setUser($student);
443 \core_tag_index_builder
::reset_caches();
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
);
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
);
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
);
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
);
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);
508 public function test_mod_glossary_can_delete_entry_users() {
509 $this->resetAfterTest();
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
]);
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
);
523 // Test student can delete.
524 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context));
526 // Test teacher can delete.
527 $this->setUser($teacher);
528 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context));
530 // Test admin can delete.
531 $this->setAdminUser();
532 $this->assertTrue(mod_glossary_can_delete_entry($entry, $glossary, $context));
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));
539 $this->expectExceptionMessage(get_string('nopermissiontodelentry', 'error'));
540 mod_glossary_can_delete_entry($entry, $glossary, $context, false);
543 public function test_mod_glossary_can_delete_entry_edit_period() {
545 $this->resetAfterTest();
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]);
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
);
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));
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));
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));
570 $entry->timecreated
= time() - 2 * $CFG->maxeditingtime
;
571 $this->expectExceptionMessage(get_string('errdeltimeexpired', 'glossary'));
572 mod_glossary_can_delete_entry($entry, $glossary, $context, false);
575 public function test_mod_glossary_delete_entry() {
577 $this->resetAfterTest();
578 require_once($CFG->dirroot
. '/rating/lib.php');
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');
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
);
594 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
595 $this->setUser($student1);
597 // Create entry with tags and rating.
598 $entry = $gg->create_content(
600 ['approved' => 1, 'userid' => $student1->id
, 'tags' => ['Cats', 'Dogs']],
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);
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);
623 $this->assertEquals('\mod_glossary\event\entry_deleted', $event->eventname
);
624 $this->assertEquals($entry->id
, $event->objectid
);
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'));
634 public function test_mod_glossary_delete_entry_imported() {
636 $this->resetAfterTest();
638 // Create required data.
639 $course = $this->getDataGenerator()->create_course();
640 $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
642 $glossary1 = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id
]);
643 $glossary2 = $this->getDataGenerator()->create_module('glossary', ['course' => $course->id
]);
645 $context = \context_module
::instance($glossary2->cmid
);
646 $cm = get_coursemodule_from_instance('glossary', $glossary2->id
);
648 $gg = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
649 $this->setUser($student);
651 $entry1 = $gg->create_content($glossary1);
652 $entry2 = $gg->create_content(
654 ['approved' => 1, 'userid' => $student->id
, 'sourceglossaryid' => $glossary1->id
, 'tags' => ['Cats', 'Dogs']]
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);
663 $this->assertEquals('\mod_glossary\event\entry_deleted', $event->eventname
);
664 $this->assertEquals($entry2->id
, $event->objectid
);
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
]));
672 $this->assertEmpty(\core_tag_tag
::get_by_name(0, 'Cats'));
675 public function test_mod_glossary_can_update_entry_users() {
676 $this->resetAfterTest();
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
));
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
);
691 // Test student can update.
692 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
694 // Test teacher can update.
695 $this->setUser($teacher);
696 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
698 // Test admin can update.
699 $this->setAdminUser();
700 $this->assertTrue(mod_glossary_can_update_entry($entry, $glossary, $context, $cm));
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));
707 $this->expectExceptionMessage(get_string('errcannoteditothers', 'glossary'));
708 mod_glossary_can_update_entry($entry, $glossary, $context, $cm, false);
711 public function test_mod_glossary_can_update_entry_edit_period() {
713 $this->resetAfterTest();
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));
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
);
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));
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));
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));
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);
744 public function test_prepare_entry_for_edition() {
746 $this->resetAfterTest(true);
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');
752 $this->setAdminUser();
753 $aliases = ['alias1', 'alias2'];
754 $entry = $gg->create_content(
756 ['approved' => 1, 'userid' => $USER->id
],
760 $cat1 = $gg->create_category($glossary, [], [$entry]);
761 $gg->create_category($glossary);
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);