Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
 
11 efrain 41
    public function test_glossary_view(): void {
1 efrain 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
 
11 efrain 97
    public function test_glossary_entry_view(): void {
1 efrain 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
 
11 efrain 119
    public function test_glossary_core_calendar_provide_event_action(): void {
1 efrain 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
 
11 efrain 145
    public function test_glossary_core_calendar_provide_event_action_as_non_user(): void {
1 efrain 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
 
11 efrain 173
    public function test_glossary_core_calendar_provide_event_action_for_user(): void {
1 efrain 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
 
11 efrain 210
    public function test_glossary_core_calendar_provide_event_action_in_hidden_section(): void {
1 efrain 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
 
11 efrain 240
    public function test_glossary_core_calendar_provide_event_action_already_completed(): void {
1 efrain 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
 
11 efrain 274
    public function test_glossary_core_calendar_provide_event_action_already_completed_for_user(): void {
1 efrain 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
     */
11 efrain 339
    public function test_mod_glossary_completion_get_active_rule_descriptions(): void {
1 efrain 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
 
11 efrain 372
    public function test_mod_glossary_get_tagged_entries(): void {
1 efrain 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
 
11 efrain 471
    public function test_glossary_get_entries_search(): void {
1 efrain 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
 
11 efrain 508
    public function test_mod_glossary_can_delete_entry_users(): void {
1 efrain 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
 
11 efrain 543
    public function test_mod_glossary_can_delete_entry_edit_period(): void {
1 efrain 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
 
11 efrain 575
    public function test_mod_glossary_delete_entry(): void {
1 efrain 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
 
11 efrain 634
    public function test_mod_glossary_delete_entry_imported(): void {
1 efrain 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
 
11 efrain 675
    public function test_mod_glossary_can_update_entry_users(): void {
1 efrain 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
 
11 efrain 711
    public function test_mod_glossary_can_update_entry_edit_period(): void {
1 efrain 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
 
11 efrain 744
    public function test_prepare_entry_for_edition(): void {
1 efrain 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
}