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
 * Unit tests for (some of) mod/quiz/locallib.php.
19
 *
20
 * @package    mod_quiz
21
 * @category   test
22
 * @copyright  2008 Tim Hunt
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
namespace mod_quiz;
26
 
27
use mod_quiz\output\renderer;
28
use mod_quiz\question\display_options;
29
 
30
defined('MOODLE_INTERNAL') || die();
31
 
32
global $CFG;
33
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
34
require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php');
35
 
36
/**
37
 * Unit tests for (some of) mod/quiz/locallib.php.
38
 *
39
 * @copyright  2008 Tim Hunt
40
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41
 */
42
class locallib_test extends \advanced_testcase {
43
 
44
    use \quiz_question_helper_test_trait;
45
 
11 efrain 46
    public function test_quiz_rescale_grade(): void {
1 efrain 47
        $quiz = new \stdClass();
48
        $quiz->decimalpoints = 2;
49
        $quiz->questiondecimalpoints = 3;
50
        $quiz->grade = 10;
51
        $quiz->sumgrades = 10;
52
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.12345678);
53
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.12, 2));
54
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'),
55
            format_float(0.123, 3));
56
        $quiz->sumgrades = 5;
57
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.24691356);
58
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.25, 2));
59
        $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'),
60
            format_float(0.247, 3));
61
    }
62
 
63
    public function quiz_attempt_state_data_provider() {
64
        return [
65
            [quiz_attempt::IN_PROGRESS, null, null, display_options::DURING],
66
            [quiz_attempt::FINISHED, -90, null, display_options::IMMEDIATELY_AFTER],
67
            [quiz_attempt::FINISHED, -7200, null, display_options::LATER_WHILE_OPEN],
68
            [quiz_attempt::FINISHED, -7200, 3600, display_options::LATER_WHILE_OPEN],
69
            [quiz_attempt::FINISHED, -30, 30, display_options::IMMEDIATELY_AFTER],
70
            [quiz_attempt::FINISHED, -90, -30, display_options::AFTER_CLOSE],
71
            [quiz_attempt::FINISHED, -7200, -3600, display_options::AFTER_CLOSE],
72
            [quiz_attempt::FINISHED, -90, -3600, display_options::AFTER_CLOSE],
73
            [quiz_attempt::ABANDONED, -10000000, null, display_options::LATER_WHILE_OPEN],
74
            [quiz_attempt::ABANDONED, -7200, 3600, display_options::LATER_WHILE_OPEN],
75
            [quiz_attempt::ABANDONED, -7200, -3600, display_options::AFTER_CLOSE],
76
        ];
77
    }
78
 
79
    /**
80
     * @dataProvider quiz_attempt_state_data_provider
81
     *
82
     * @param string $attemptstate as in the quiz_attempts.state DB column.
83
     * @param int|null $relativetimefinish time relative to now when the attempt finished, or null for 0.
84
     * @param int|null $relativetimeclose time relative to now when the quiz closes, or null for 0.
85
     * @param int $expectedstate expected result. One of the display_options constants.
86
     * @covers ::quiz_attempt_state
87
     */
88
    public function test_quiz_attempt_state(string $attemptstate,
11 efrain 89
            ?int $relativetimefinish, ?int $relativetimeclose, int $expectedstate): void {
1 efrain 90
 
91
        $attempt = new \stdClass();
92
        $attempt->state = $attemptstate;
93
        if ($relativetimefinish === null) {
94
            $attempt->timefinish = 0;
95
        } else {
96
            $attempt->timefinish = time() + $relativetimefinish;
97
        }
98
 
99
        $quiz = new \stdClass();
100
        if ($relativetimeclose === null) {
101
            $quiz->timeclose = 0;
102
        } else {
103
            $quiz->timeclose = time() + $relativetimeclose;
104
        }
105
 
106
        $this->assertEquals($expectedstate, quiz_attempt_state($quiz, $attempt));
107
    }
108
 
109
    /**
110
     * @covers ::quiz_question_tostring
111
     */
11 efrain 112
    public function test_quiz_question_tostring(): void {
1 efrain 113
        $question = new \stdClass();
114
        $question->qtype = 'multichoice';
115
        $question->name = 'The question name';
116
        $question->questiontext = '<p>What sort of <b>inequality</b> is x &lt; y<img alt="?" src="..."></p>';
117
        $question->questiontextformat = FORMAT_HTML;
118
 
119
        $summary = quiz_question_tostring($question);
120
        $this->assertEquals('<span class="questionname">The question name</span> ' .
121
                '<span class="questiontext">What sort of INEQUALITY is x &lt; y[?]' . "\n" . '</span>', $summary);
122
    }
123
 
124
    /**
125
     * @covers ::quiz_question_tostring
126
     */
11 efrain 127
    public function test_quiz_question_tostring_does_not_filter(): void {
1 efrain 128
        $question = new \stdClass();
129
        $question->qtype = 'multichoice';
130
        $question->name = 'The question name';
131
        $question->questiontext = '<p>No emoticons here :-)</p>';
132
        $question->questiontextformat = FORMAT_HTML;
133
 
134
        $summary = quiz_question_tostring($question);
135
        $this->assertEquals('<span class="questionname">The question name</span> ' .
136
                '<span class="questiontext">No emoticons here :-)' . "\n</span>", $summary);
137
    }
138
 
139
    /**
140
     * Test quiz_view
141
     * @return void
142
     */
11 efrain 143
    public function test_quiz_view(): void {
1 efrain 144
        global $CFG;
145
 
146
        $CFG->enablecompletion = 1;
147
        $this->resetAfterTest();
148
 
149
        $this->setAdminUser();
150
        // Setup test data.
151
        $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
152
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id],
153
                                                            ['completion' => 2, 'completionview' => 1]);
154
        $context = \context_module::instance($quiz->cmid);
155
        $cm = get_coursemodule_from_instance('quiz', $quiz->id);
156
 
157
        // Trigger and capture the event.
158
        $sink = $this->redirectEvents();
159
 
160
        quiz_view($quiz, $course, $cm, $context);
161
 
162
        $events = $sink->get_events();
163
        // 2 additional events thanks to completion.
164
        $this->assertCount(3, $events);
165
        $event = array_shift($events);
166
 
167
        // Checking that the event contains the expected values.
168
        $this->assertInstanceOf('\mod_quiz\event\course_module_viewed', $event);
169
        $this->assertEquals($context, $event->get_context());
170
        $moodleurl = new \moodle_url('/mod/quiz/view.php', ['id' => $cm->id]);
171
        $this->assertEquals($moodleurl, $event->get_url());
172
        $this->assertEventContextNotUsed($event);
173
        $this->assertNotEmpty($event->get_name());
174
        // Check completion status.
175
        $completion = new \completion_info($course);
176
        $completiondata = $completion->get_data($cm);
177
        $this->assertEquals(1, $completiondata->completionstate);
178
    }
179
 
180
    /**
181
     * Return false when there are not overrides for this quiz instance.
182
     */
11 efrain 183
    public function test_quiz_is_overriden_calendar_event_no_override(): void {
1 efrain 184
        global $CFG, $DB;
185
 
186
        $this->resetAfterTest();
187
        $this->setAdminUser();
188
 
189
        $generator = $this->getDataGenerator();
190
        $user = $generator->create_user();
191
        $course = $generator->create_course();
192
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
193
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
194
 
195
        $event = new \calendar_event((object)[
196
            'modulename' => 'quiz',
197
            'instance' => $quiz->id,
198
            'userid' => $user->id
199
        ]);
200
 
201
        $this->assertFalse(quiz_is_overriden_calendar_event($event));
202
    }
203
 
204
    /**
205
     * Return false if the given event isn't an quiz module event.
206
     */
11 efrain 207
    public function test_quiz_is_overriden_calendar_event_no_module_event(): void {
1 efrain 208
        global $CFG, $DB;
209
 
210
        $this->resetAfterTest();
211
        $this->setAdminUser();
212
 
213
        $generator = $this->getDataGenerator();
214
        $user = $generator->create_user();
215
        $course = $generator->create_course();
216
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
217
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
218
 
219
        $event = new \calendar_event((object)[
220
            'userid' => $user->id
221
        ]);
222
 
223
        $this->assertFalse(quiz_is_overriden_calendar_event($event));
224
    }
225
 
226
    /**
227
     * Return false if there is overrides for this use but they belong to another quiz
228
     * instance.
229
     */
11 efrain 230
    public function test_quiz_is_overriden_calendar_event_different_quiz_instance(): void {
1 efrain 231
        global $CFG, $DB;
232
 
233
        $this->resetAfterTest();
234
        $this->setAdminUser();
235
 
236
        $generator = $this->getDataGenerator();
237
        $user = $generator->create_user();
238
        $course = $generator->create_course();
239
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
240
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
241
        $quiz2 = $quizgenerator->create_instance(['course' => $course->id]);
242
 
243
        $event = new \calendar_event((object) [
244
            'modulename' => 'quiz',
245
            'instance' => $quiz->id,
246
            'userid' => $user->id
247
        ]);
248
 
249
        $record = (object) [
250
            'quiz' => $quiz2->id,
251
            'userid' => $user->id
252
        ];
253
 
254
        $DB->insert_record('quiz_overrides', $record);
255
 
256
        $this->assertFalse(quiz_is_overriden_calendar_event($event));
257
    }
258
 
259
    /**
260
     * Return true if there is a user override for this event and quiz instance.
261
     */
11 efrain 262
    public function test_quiz_is_overriden_calendar_event_user_override(): void {
1 efrain 263
        global $CFG, $DB;
264
 
265
        $this->resetAfterTest();
266
        $this->setAdminUser();
267
 
268
        $generator = $this->getDataGenerator();
269
        $user = $generator->create_user();
270
        $course = $generator->create_course();
271
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
272
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
273
 
274
        $event = new \calendar_event((object) [
275
            'modulename' => 'quiz',
276
            'instance' => $quiz->id,
277
            'userid' => $user->id
278
        ]);
279
 
280
        $record = (object) [
281
            'quiz' => $quiz->id,
282
            'userid' => $user->id
283
        ];
284
 
285
        $DB->insert_record('quiz_overrides', $record);
286
 
287
        $this->assertTrue(quiz_is_overriden_calendar_event($event));
288
    }
289
 
290
    /**
291
     * Return true if there is a group override for the event and quiz instance.
292
     */
11 efrain 293
    public function test_quiz_is_overriden_calendar_event_group_override(): void {
1 efrain 294
        global $CFG, $DB;
295
 
296
        $this->resetAfterTest();
297
        $this->setAdminUser();
298
 
299
        $generator = $this->getDataGenerator();
300
        $user = $generator->create_user();
301
        $course = $generator->create_course();
302
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
303
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
304
        $group = $this->getDataGenerator()->create_group(['courseid' => $quiz->course]);
305
        $groupid = $group->id;
306
        $userid = $user->id;
307
 
308
        $event = new \calendar_event((object) [
309
            'modulename' => 'quiz',
310
            'instance' => $quiz->id,
311
            'groupid' => $groupid
312
        ]);
313
 
314
        $record = (object) [
315
            'quiz' => $quiz->id,
316
            'groupid' => $groupid
317
        ];
318
 
319
        $DB->insert_record('quiz_overrides', $record);
320
 
321
        $this->assertTrue(quiz_is_overriden_calendar_event($event));
322
    }
323
 
324
    /**
325
     * Test test_quiz_get_user_timeclose().
326
     */
11 efrain 327
    public function test_quiz_get_user_timeclose(): void {
1 efrain 328
        global $DB;
329
 
330
        $this->resetAfterTest();
331
        $this->setAdminUser();
332
 
333
        $basetimestamp = time(); // The timestamp we will base the enddates on.
334
 
335
        // Create generator, course and quizzes.
336
        $student1 = $this->getDataGenerator()->create_user();
337
        $student2 = $this->getDataGenerator()->create_user();
338
        $student3 = $this->getDataGenerator()->create_user();
339
        $teacher = $this->getDataGenerator()->create_user();
340
        $course = $this->getDataGenerator()->create_course();
341
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
342
 
343
        // Both quizzes close in two hours.
344
        $quiz1 = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => $basetimestamp + 7200]);
345
        $quiz2 = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => $basetimestamp + 7200]);
346
        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
347
        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
348
 
349
        $student1id = $student1->id;
350
        $student2id = $student2->id;
351
        $student3id = $student3->id;
352
        $teacherid = $teacher->id;
353
 
354
        // Users enrolments.
355
        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
356
        $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
357
        $this->getDataGenerator()->enrol_user($student1id, $course->id, $studentrole->id, 'manual');
358
        $this->getDataGenerator()->enrol_user($student2id, $course->id, $studentrole->id, 'manual');
359
        $this->getDataGenerator()->enrol_user($student3id, $course->id, $studentrole->id, 'manual');
360
        $this->getDataGenerator()->enrol_user($teacherid, $course->id, $teacherrole->id, 'manual');
361
 
362
        // Create groups.
363
        $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
364
        $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
365
        $group1id = $group1->id;
366
        $group2id = $group2->id;
367
        $this->getDataGenerator()->create_group_member(['userid' => $student1id, 'groupid' => $group1id]);
368
        $this->getDataGenerator()->create_group_member(['userid' => $student2id, 'groupid' => $group2id]);
369
 
370
        // Group 1 gets an group override for quiz 1 to close in three hours.
371
        $record1 = (object) [
372
            'quiz' => $quiz1->id,
373
            'groupid' => $group1id,
374
            'timeclose' => $basetimestamp + 10800 // In three hours.
375
        ];
376
        $DB->insert_record('quiz_overrides', $record1);
377
 
378
        // Let's test quiz 1 closes in three hours for user student 1 since member of group 1.
379
        // Quiz 2 closes in two hours.
380
        $this->setUser($student1id);
381
        $params = new \stdClass();
382
 
383
        $comparearray = [];
384
        $object = new \stdClass();
385
        $object->id = $quiz1->id;
386
        $object->usertimeclose = $basetimestamp + 10800; // The overriden timeclose for quiz 1.
387
 
388
        $comparearray[$quiz1->id] = $object;
389
 
390
        $object = new \stdClass();
391
        $object->id = $quiz2->id;
392
        $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2.
393
 
394
        $comparearray[$quiz2->id] = $object;
395
 
396
        $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
397
 
398
        // Let's test quiz 1 closes in two hours (the original value) for user student 3 since member of no group.
399
        $this->setUser($student3id);
400
        $params = new \stdClass();
401
 
402
        $comparearray = [];
403
        $object = new \stdClass();
404
        $object->id = $quiz1->id;
405
        $object->usertimeclose = $basetimestamp + 7200; // The original timeclose for quiz 1.
406
 
407
        $comparearray[$quiz1->id] = $object;
408
 
409
        $object = new \stdClass();
410
        $object->id = $quiz2->id;
411
        $object->usertimeclose = $basetimestamp + 7200; // The original timeclose for quiz 2.
412
 
413
        $comparearray[$quiz2->id] = $object;
414
 
415
        $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
416
 
417
        // User 2 gets an user override for quiz 1 to close in four hours.
418
        $record2 = (object) [
419
            'quiz' => $quiz1->id,
420
            'userid' => $student2id,
421
            'timeclose' => $basetimestamp + 14400 // In four hours.
422
        ];
423
        $DB->insert_record('quiz_overrides', $record2);
424
 
425
        // Let's test quiz 1 closes in four hours for user student 2 since personally overriden.
426
        // Quiz 2 closes in two hours.
427
        $this->setUser($student2id);
428
 
429
        $comparearray = [];
430
        $object = new \stdClass();
431
        $object->id = $quiz1->id;
432
        $object->usertimeclose = $basetimestamp + 14400; // The overriden timeclose for quiz 1.
433
 
434
        $comparearray[$quiz1->id] = $object;
435
 
436
        $object = new \stdClass();
437
        $object->id = $quiz2->id;
438
        $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2.
439
 
440
        $comparearray[$quiz2->id] = $object;
441
 
442
        $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
443
 
444
        // Let's test a teacher sees the original times.
445
        // Quiz 1 and quiz 2 close in two hours.
446
        $this->setUser($teacherid);
447
 
448
        $comparearray = [];
449
        $object = new \stdClass();
450
        $object->id = $quiz1->id;
451
        $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 1.
452
 
453
        $comparearray[$quiz1->id] = $object;
454
 
455
        $object = new \stdClass();
456
        $object->id = $quiz2->id;
457
        $object->usertimeclose = $basetimestamp + 7200; // The unchanged timeclose for quiz 2.
458
 
459
        $comparearray[$quiz2->id] = $object;
460
 
461
        $this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
462
    }
463
 
464
    /**
465
     * This function creates a quiz with some standard (non-random) and some random questions.
466
     * The standard questions are created first and then random questions follow them.
467
     * So in a quiz with 3 standard question and 2 random question, the first random question is at slot 4.
468
     *
469
     * @param int $qnum Number of standard questions that should be created in the quiz.
470
     * @param int $randomqnum Number of random questions that should be created in the quiz.
471
     * @param array $questiontags Tags to be used for random questions.
472
     *      This is an array in the following format:
473
     *      [
474
     *          0 => ['foo', 'bar'],
475
     *          1 => ['baz', 'qux']
476
     *      ]
477
     * @param string[] $unusedtags Some additional tags to be created.
478
     * @return array An array of 2 elements: $quiz and $tagobjects.
479
     *      $tagobjects is an associative array of all created tag objects with its key being tag names.
480
     */
481
    private function setup_quiz_and_tags($qnum, $randomqnum, $questiontags = [], $unusedtags = []) {
482
        global $SITE;
483
 
484
        $tagobjects = [];
485
 
486
        // Get all the tags that need to be created.
487
        $alltags = [];
488
        foreach ($questiontags as $questiontag) {
489
            $alltags = array_merge($alltags, $questiontag);
490
        }
491
        $alltags = array_merge($alltags, $unusedtags);
492
        $alltags = array_unique($alltags);
493
 
494
        // Create tags.
495
        foreach ($alltags as $tagname) {
496
            $tagrecord = [
497
                'isstandard' => 1,
498
                'flag' => 0,
499
                'rawname' => $tagname,
500
                'description' => $tagname . ' desc'
501
            ];
502
            $tagobjects[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
503
        }
504
 
505
        // Create a quiz.
506
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
507
        $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]);
508
 
509
        // Create a question category in the system context.
510
        $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
511
        $cat = $questiongenerator->create_question_category();
512
 
513
        // Setup standard questions.
514
        for ($i = 0; $i < $qnum; $i++) {
515
            $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
516
            quiz_add_quiz_question($question->id, $quiz);
517
        }
518
        // Setup random questions.
519
        for ($i = 0; $i < $randomqnum; $i++) {
520
            // Just create a standard question first, so there would be enough questions to pick a random question from.
521
            $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
522
            $tagids = [];
523
            if (!empty($questiontags[$i])) {
524
                foreach ($questiontags[$i] as $tagname) {
525
                    $tagids[] = $tagobjects[$tagname]->id;
526
                }
527
            }
528
            $this->add_random_questions($quiz->id, 0, $cat->id, 1);
529
        }
530
 
531
        return [$quiz, $tagobjects];
532
    }
533
 
11 efrain 534
    public function test_quiz_override_summary(): void {
1 efrain 535
        global $DB, $PAGE;
536
        $this->resetAfterTest();
537
        $generator = $this->getDataGenerator();
538
        /** @var mod_quiz_generator $quizgenerator */
539
        $quizgenerator = $generator->get_plugin_generator('mod_quiz');
540
        /** @var renderer $renderer */
541
        $renderer = $PAGE->get_renderer('mod_quiz');
542
 
543
        // Course with quiz and a group - plus some others, to verify they don't get counted.
544
        $course = $generator->create_course();
545
        $quiz = $quizgenerator->create_instance(['course' => $course->id, 'groupmode' => SEPARATEGROUPS]);
546
        $cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id);
547
        $group = $generator->create_group(['courseid' => $course->id]);
548
        $othergroup = $generator->create_group(['courseid' => $course->id]);
549
        $otherquiz = $quizgenerator->create_instance(['course' => $course->id]);
550
 
551
        // Initial test (as admin) with no data.
552
        $this->setAdminUser();
553
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'],
554
                quiz_override_summary($quiz, $cm));
555
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
556
                quiz_override_summary($quiz, $cm, $group->id));
557
 
558
        // Editing teacher.
559
        $teacher = $generator->create_user();
560
        $generator->enrol_user($teacher->id, $course->id, 'editingteacher');
561
 
562
        // Non-editing teacher.
563
        $tutor = $generator->create_user();
564
        $generator->enrol_user($tutor->id, $course->id, 'teacher');
565
        $generator->create_group_member(['userid' => $tutor->id, 'groupid' => $group->id]);
566
 
567
        // Three students.
568
        $student1 = $generator->create_user();
569
        $generator->enrol_user($student1->id, $course->id, 'student');
570
        $generator->create_group_member(['userid' => $student1->id, 'groupid' => $group->id]);
571
 
572
        $student2 = $generator->create_user();
573
        $generator->enrol_user($student2->id, $course->id, 'student');
574
        $generator->create_group_member(['userid' => $student2->id, 'groupid' => $othergroup->id]);
575
 
576
        $student3 = $generator->create_user();
577
        $generator->enrol_user($student3->id, $course->id, 'student');
578
 
579
        // Initial test now users exist, but before overrides.
580
        // Test as teacher.
581
        $this->setUser($teacher);
582
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'allgroups'],
583
                quiz_override_summary($quiz, $cm));
584
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
585
                quiz_override_summary($quiz, $cm, $group->id));
586
 
587
        // Test as tutor.
588
        $this->setUser($tutor);
589
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'somegroups'],
590
                quiz_override_summary($quiz, $cm));
591
        $this->assertEquals(['group' => 0, 'user' => 0, 'mode' => 'onegroup'],
592
                quiz_override_summary($quiz, $cm, $group->id));
593
        $this->assertEquals('', $renderer->quiz_override_summary_links($quiz, $cm));
594
 
595
        // Quiz setting overrides for students 1 and 3.
596
        $quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student1->id, 'attempts' => 2]);
597
        $quizgenerator->create_override(['quiz' => $quiz->id, 'userid' => $student3->id, 'attempts' => 2]);
598
        $quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $group->id, 'attempts' => 3]);
599
        $quizgenerator->create_override(['quiz' => $quiz->id, 'groupid' => $othergroup->id, 'attempts' => 3]);
600
        $quizgenerator->create_override(['quiz' => $otherquiz->id, 'userid' => $student2->id, 'attempts' => 2]);
601
 
602
        // Test as teacher.
603
        $this->setUser($teacher);
604
        $this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'],
605
                quiz_override_summary($quiz, $cm));
606
        $this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)',
607
                // Links checked by Behat, so strip them for these tests.
608
                html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
609
        $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'],
610
                quiz_override_summary($quiz, $cm, $group->id));
611
        $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group',
612
                html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false));
613
 
614
        // Test as tutor.
615
        $this->setUser($tutor);
616
        $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'somegroups'],
617
                quiz_override_summary($quiz, $cm));
618
        $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for your groups',
619
                html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
620
        $this->assertEquals(['group' => 1, 'user' => 1, 'mode' => 'onegroup'],
621
                quiz_override_summary($quiz, $cm, $group->id));
622
        $this->assertEquals('Settings overrides exist (Groups: 1, Users: 1) for this group',
623
                html_to_text($renderer->quiz_override_summary_links($quiz, $cm, $group->id), 0, false));
624
 
625
        // Now set the quiz to be group mode: no groups, and re-test as tutor.
626
        // In this case, the tutor should see all groups.
627
        $DB->set_field('course_modules', 'groupmode', NOGROUPS, ['id' => $cm->id]);
628
        $cm = get_coursemodule_from_id('quiz', $quiz->cmid, $course->id);
629
 
630
        $this->assertEquals(['group' => 2, 'user' => 2, 'mode' => 'allgroups'],
631
                quiz_override_summary($quiz, $cm));
632
        $this->assertEquals('Settings overrides exist (Groups: 2, Users: 2)',
633
                html_to_text($renderer->quiz_override_summary_links($quiz, $cm), 0, false));
634
    }
635
 
636
    /**
637
     *  Test quiz_send_confirmation function.
638
     */
11 efrain 639
    public function test_quiz_send_confirmation(): void {
1 efrain 640
        global $CFG, $DB;
641
 
642
        $this->resetAfterTest();
643
        $this->setAdminUser();
644
        $this->preventResetByRollback();
645
 
646
        $course = $this->getDataGenerator()->create_course();
647
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
648
        $quiz = $quizgenerator->create_instance(['course' => $course->id]);
649
        $cm = get_coursemodule_from_instance('quiz', $quiz->id);
650
 
651
        $recipient = $this->getDataGenerator()->create_user(['email' => 'student@example.com']);
652
 
653
        // Allow recipent to receive email confirm submission.
654
        $studentrole = $DB->get_record('role', ['shortname' => 'student']);
655
        assign_capability('mod/quiz:emailconfirmsubmission', CAP_ALLOW, $studentrole->id,
656
            \context_course::instance($course->id), true);
657
        $this->getDataGenerator()->enrol_user($recipient->id, $course->id, $studentrole->id, 'manual');
658
 
659
        $timenow = time();
660
        $data = new \stdClass();
661
        // Course info.
662
        $data->courseid        = $course->id;
663
        $data->coursename      = $course->fullname;
664
        // Quiz info.
665
        $data->quizname        = $quiz->name;
666
        $data->quizurl         = $CFG->wwwroot . '/mod/quiz/view.php?id=' . $cm->id;
667
        $data->quizid          = $quiz->id;
668
        $data->quizcmid        = $quiz->cmid;
669
        $data->attemptid       = 1;
670
        $data->submissiontime = userdate($timenow);
671
 
672
        $sink = $this->redirectEmails();
673
        quiz_send_confirmation($recipient, $data, true);
674
        $messages = $sink->get_messages();
675
        $message = reset($messages);
676
        $this->assertStringContainsString("Thank you for submitting your answers" ,
677
            quoted_printable_decode($message->body));
678
        $sink->close();
679
 
680
        $sink = $this->redirectEmails();
681
        quiz_send_confirmation($recipient, $data, false);
682
        $messages = $sink->get_messages();
683
        $message = reset($messages);
684
        $this->assertStringContainsString("Your answers were submitted automatically" ,
685
            quoted_printable_decode($message->body));
686
        $sink->close();
687
    }
688
}