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
 * Quiz events tests.
19
 *
20
 * @package    mod_quiz
21
 * @category   phpunit
22
 * @copyright  2013 Adrian Greeve
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
 
26
namespace mod_quiz\event;
27
 
28
use mod_quiz\quiz_attempt;
29
use mod_quiz\quiz_settings;
30
use context_module;
31
 
32
/**
33
 * Unit tests for quiz events.
34
 *
35
 * @package    mod_quiz
36
 * @category   phpunit
37
 * @copyright  2013 Adrian Greeve
38
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39
 */
40
class events_test extends \advanced_testcase {
41
 
42
    /**
43
     * Set up a quiz.
44
     *
45
     * The quiz contains two questions, a short-answer one and a numerical one.
46
     *
47
     * @return quiz_settings the generated quiz.
48
     */
49
    protected function prepare_quiz() {
50
 
51
        $this->resetAfterTest(true);
52
 
53
        // Create a course
54
        $course = $this->getDataGenerator()->create_course();
55
 
56
        // Make a quiz.
57
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
58
 
59
        $quiz = $quizgenerator->create_instance(['course' => $course->id, 'questionsperpage' => 0,
60
                'grade' => 100.0, 'sumgrades' => 2]);
61
 
62
        get_coursemodule_from_instance('quiz', $quiz->id, $course->id);
63
 
64
        // Create a couple of questions.
65
        $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
66
 
67
        $cat = $questiongenerator->create_question_category();
68
        $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
69
        $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
70
 
71
        // Add them to the quiz.
72
        quiz_add_quiz_question($saq->id, $quiz);
73
        quiz_add_quiz_question($numq->id, $quiz);
74
 
75
        // Make a user to do the quiz.
76
        $user1 = $this->getDataGenerator()->create_user();
77
        $this->setUser($user1);
78
 
79
        return quiz_settings::create($quiz->id, $user1->id);
80
    }
81
 
82
    /**
83
     * Setup a quiz attempt at the quiz created by {@link prepare_quiz()}.
84
     *
85
     * @param \mod_quiz\quiz_settings $quizobj the generated quiz.
86
     * @param bool $ispreview Make the attempt a preview attempt when true.
87
     * @return array with three elements, array($quizobj, $quba, $attempt)
88
     */
89
    protected function prepare_quiz_attempt($quizobj, $ispreview = false) {
90
        // Start the attempt.
91
        $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
92
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
93
 
94
        $timenow = time();
95
        $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, $ispreview);
96
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
97
        quiz_attempt_save_started($quizobj, $quba, $attempt);
98
 
99
        return [$quizobj, $quba, $attempt];
100
    }
101
 
102
    /**
103
     * Setup some convenience test data with a single attempt.
104
     *
105
     * @param bool $ispreview Make the attempt a preview attempt when true.
106
     * @return array with three elements, array($quizobj, $quba, $attempt)
107
     */
108
    protected function prepare_quiz_data($ispreview = false) {
109
        $quizobj = $this->prepare_quiz();
110
        return $this->prepare_quiz_attempt($quizobj, $ispreview);
111
    }
112
 
11 efrain 113
    public function test_attempt_submitted(): void {
1 efrain 114
 
115
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
116
        $attemptobj = quiz_attempt::create($attempt->id);
117
 
118
        // Catch the event.
119
        $sink = $this->redirectEvents();
120
 
121
        $timefinish = time();
122
        $attemptobj->process_finish($timefinish, false);
123
        $events = $sink->get_events();
124
        $sink->close();
125
 
126
        // Validate the event.
127
        $this->assertCount(3, $events);
128
        $event = $events[2];
129
        $this->assertInstanceOf('\mod_quiz\event\attempt_submitted', $event);
130
        $this->assertEquals('quiz_attempts', $event->objecttable);
131
        $this->assertEquals($quizobj->get_context(), $event->get_context());
132
        $this->assertEquals($attempt->userid, $event->relateduserid);
133
        $this->assertEquals(null, $event->other['submitterid']); // Should be the user, but PHP Unit complains...
134
        $this->assertEventContextNotUsed($event);
135
    }
136
 
11 efrain 137
    public function test_attempt_becameoverdue(): void {
1 efrain 138
 
139
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
140
        $attemptobj = quiz_attempt::create($attempt->id);
141
 
142
        // Catch the event.
143
        $sink = $this->redirectEvents();
144
        $timefinish = time();
145
        $attemptobj->process_going_overdue($timefinish, false);
146
        $events = $sink->get_events();
147
        $sink->close();
148
 
149
        $this->assertCount(1, $events);
150
        $event = $events[0];
151
        $this->assertInstanceOf('\mod_quiz\event\attempt_becameoverdue', $event);
152
        $this->assertEquals('quiz_attempts', $event->objecttable);
153
        $this->assertEquals($quizobj->get_context(), $event->get_context());
154
        $this->assertEquals($attempt->userid, $event->relateduserid);
155
        $this->assertNotEmpty($event->get_description());
156
        // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
157
        $this->assertEquals(null, $event->other['submitterid']);
158
        $this->assertEventContextNotUsed($event);
159
    }
160
 
11 efrain 161
    public function test_attempt_abandoned(): void {
1 efrain 162
 
163
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
164
        $attemptobj = quiz_attempt::create($attempt->id);
165
 
166
        // Catch the event.
167
        $sink = $this->redirectEvents();
168
        $timefinish = time();
169
        $attemptobj->process_abandon($timefinish, false);
170
        $events = $sink->get_events();
171
        $sink->close();
172
 
173
        $this->assertCount(1, $events);
174
        $event = $events[0];
175
        $this->assertInstanceOf('\mod_quiz\event\attempt_abandoned', $event);
176
        $this->assertEquals('quiz_attempts', $event->objecttable);
177
        $this->assertEquals($quizobj->get_context(), $event->get_context());
178
        $this->assertEquals($attempt->userid, $event->relateduserid);
179
        // Submitterid should be the user, but as we are in PHP Unit, CLI_SCRIPT is set to true which sets null in submitterid.
180
        $this->assertEquals(null, $event->other['submitterid']);
181
        $this->assertEventContextNotUsed($event);
182
    }
183
 
11 efrain 184
    public function test_attempt_started(): void {
1 efrain 185
        $quizobj = $this->prepare_quiz();
186
 
187
        $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
188
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
189
 
190
        $timenow = time();
191
        $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
192
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
193
 
194
        // Trigger and capture the event.
195
        $sink = $this->redirectEvents();
196
        quiz_attempt_save_started($quizobj, $quba, $attempt);
197
        $events = $sink->get_events();
198
        $event = reset($events);
199
 
200
        // Check that the event data is valid.
201
        $this->assertInstanceOf('\mod_quiz\event\attempt_started', $event);
202
        $this->assertEquals('quiz_attempts', $event->objecttable);
203
        $this->assertEquals($attempt->id, $event->objectid);
204
        $this->assertEquals($attempt->userid, $event->relateduserid);
205
        $this->assertEquals($quizobj->get_context(), $event->get_context());
206
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
207
    }
208
 
209
    /**
210
     * Test the attempt question restarted event.
211
     *
212
     * There is no external API for replacing a question, so the unit test will simply
213
     * create and trigger the event and ensure the event data is returned as expected.
214
     */
11 efrain 215
    public function test_attempt_question_restarted(): void {
1 efrain 216
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
217
 
218
        $params = [
219
            'objectid' => 1,
220
            'relateduserid' => 2,
221
            'courseid' => $quizobj->get_courseid(),
222
            'context' => \context_module::instance($quizobj->get_cmid()),
223
            'other' => [
224
                'quizid' => $quizobj->get_quizid(),
225
                'page' => 2,
226
                'slot' => 3,
227
                'newquestionid' => 2
228
            ]
229
        ];
230
        $event = \mod_quiz\event\attempt_question_restarted::create($params);
231
 
232
        // Trigger and capture the event.
233
        $sink = $this->redirectEvents();
234
        $event->trigger();
235
        $events = $sink->get_events();
236
        $event = reset($events);
237
 
238
        // Check that the event data is valid.
239
        $this->assertInstanceOf('\mod_quiz\event\attempt_question_restarted', $event);
240
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
241
        $this->assertEventContextNotUsed($event);
242
    }
243
 
244
    /**
245
     * Test the attempt updated event.
246
     *
247
     * There is no external API for updating an attempt, so the unit test will simply
248
     * create and trigger the event and ensure the event data is returned as expected.
249
     */
11 efrain 250
    public function test_attempt_updated(): void {
1 efrain 251
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
252
 
253
        $params = [
254
            'objectid' => 1,
255
            'relateduserid' => 2,
256
            'courseid' => $quizobj->get_courseid(),
257
            'context' => \context_module::instance($quizobj->get_cmid()),
258
            'other' => [
259
                'quizid' => $quizobj->get_quizid(),
260
                'page' => 0
261
            ]
262
        ];
263
        $event = \mod_quiz\event\attempt_updated::create($params);
264
 
265
        // Trigger and capture the event.
266
        $sink = $this->redirectEvents();
267
        $event->trigger();
268
        $events = $sink->get_events();
269
        $event = reset($events);
270
 
271
        // Check that the event data is valid.
272
        $this->assertInstanceOf('\mod_quiz\event\attempt_updated', $event);
273
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
274
        $this->assertEventContextNotUsed($event);
275
    }
276
 
277
    /**
278
     * Test the attempt auto-saved event.
279
     *
280
     * There is no external API for auto-saving an attempt, so the unit test will simply
281
     * create and trigger the event and ensure the event data is returned as expected.
282
     */
11 efrain 283
    public function test_attempt_autosaved(): void {
1 efrain 284
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
285
 
286
        $params = [
287
            'objectid' => 1,
288
            'relateduserid' => 2,
289
            'courseid' => $quizobj->get_courseid(),
290
            'context' => \context_module::instance($quizobj->get_cmid()),
291
            'other' => [
292
                'quizid' => $quizobj->get_quizid(),
293
                'page' => 0
294
            ]
295
        ];
296
 
297
        $event = \mod_quiz\event\attempt_autosaved::create($params);
298
 
299
        // Trigger and capture the event.
300
        $sink = $this->redirectEvents();
301
        $event->trigger();
302
        $events = $sink->get_events();
303
        $event = reset($events);
304
 
305
        // Check that the event data is valid.
306
        $this->assertInstanceOf('\mod_quiz\event\attempt_autosaved', $event);
307
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
308
        $this->assertEventContextNotUsed($event);
309
    }
310
 
311
    /**
312
     * Test the edit page viewed event.
313
     *
314
     * There is no external API for updating a quiz, so the unit test will simply
315
     * create and trigger the event and ensure the event data is returned as expected.
316
     */
11 efrain 317
    public function test_edit_page_viewed(): void {
1 efrain 318
        $this->resetAfterTest();
319
 
320
        $this->setAdminUser();
321
        $course = $this->getDataGenerator()->create_course();
322
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
323
 
324
        $params = [
325
            'courseid' => $course->id,
326
            'context' => \context_module::instance($quiz->cmid),
327
            'other' => [
328
                'quizid' => $quiz->id
329
            ]
330
        ];
331
        $event = \mod_quiz\event\edit_page_viewed::create($params);
332
 
333
        // Trigger and capture the event.
334
        $sink = $this->redirectEvents();
335
        $event->trigger();
336
        $events = $sink->get_events();
337
        $event = reset($events);
338
 
339
        // Check that the event data is valid.
340
        $this->assertInstanceOf('\mod_quiz\event\edit_page_viewed', $event);
341
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
342
        $this->assertEventContextNotUsed($event);
343
    }
344
 
345
    /**
346
     * Test the attempt deleted event.
347
     */
11 efrain 348
    public function test_attempt_deleted(): void {
1 efrain 349
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
350
 
351
        // Trigger and capture the event.
352
        $sink = $this->redirectEvents();
353
        quiz_delete_attempt($attempt, $quizobj->get_quiz());
354
        $events = $sink->get_events();
355
        $event = reset($events);
356
 
357
        // Check that the event data is valid.
358
        $this->assertInstanceOf('\mod_quiz\event\attempt_deleted', $event);
359
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
360
        $this->assertEventContextNotUsed($event);
361
    }
362
 
363
    /**
364
     * Test that preview attempt deletions are not logged.
365
     */
11 efrain 366
    public function test_preview_attempt_deleted(): void {
1 efrain 367
        // Create quiz with preview attempt.
368
        list($quizobj, $quba, $previewattempt) = $this->prepare_quiz_data(true);
369
 
370
        // Delete a preview attempt, capturing events.
371
        $sink = $this->redirectEvents();
372
        quiz_delete_attempt($previewattempt, $quizobj->get_quiz());
373
 
374
        // Verify that no events were generated.
375
        $this->assertEmpty($sink->get_events());
376
    }
377
 
378
    /**
379
     * Test the report viewed event.
380
     *
381
     * There is no external API for viewing reports, so the unit test will simply
382
     * create and trigger the event and ensure the event data is returned as expected.
383
     */
11 efrain 384
    public function test_report_viewed(): void {
1 efrain 385
        $this->resetAfterTest();
386
 
387
        $this->setAdminUser();
388
        $course = $this->getDataGenerator()->create_course();
389
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
390
 
391
        $params = [
392
            'context' => $context = \context_module::instance($quiz->cmid),
393
            'other' => [
394
                'quizid' => $quiz->id,
395
                'reportname' => 'overview'
396
            ]
397
        ];
398
        $event = \mod_quiz\event\report_viewed::create($params);
399
 
400
        // Trigger and capture the event.
401
        $sink = $this->redirectEvents();
402
        $event->trigger();
403
        $events = $sink->get_events();
404
        $event = reset($events);
405
 
406
        // Check that the event data is valid.
407
        $this->assertInstanceOf('\mod_quiz\event\report_viewed', $event);
408
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
409
        $this->assertEventContextNotUsed($event);
410
    }
411
 
412
    /**
413
     * Test the attempt reviewed event.
414
     *
415
     * There is no external API for reviewing attempts, so the unit test will simply
416
     * create and trigger the event and ensure the event data is returned as expected.
417
     */
11 efrain 418
    public function test_attempt_reviewed(): void {
1 efrain 419
        $this->resetAfterTest();
420
 
421
        $this->setAdminUser();
422
        $course = $this->getDataGenerator()->create_course();
423
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
424
 
425
        $params = [
426
            'objectid' => 1,
427
            'relateduserid' => 2,
428
            'courseid' => $course->id,
429
            'context' => \context_module::instance($quiz->cmid),
430
            'other' => [
431
                'quizid' => $quiz->id
432
            ]
433
        ];
434
        $event = \mod_quiz\event\attempt_reviewed::create($params);
435
 
436
        // Trigger and capture the event.
437
        $sink = $this->redirectEvents();
438
        $event->trigger();
439
        $events = $sink->get_events();
440
        $event = reset($events);
441
 
442
        // Check that the event data is valid.
443
        $this->assertInstanceOf('\mod_quiz\event\attempt_reviewed', $event);
444
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
445
        $this->assertEventContextNotUsed($event);
446
    }
447
 
448
    /**
449
     * Test the attempt summary viewed event.
450
     *
451
     * There is no external API for viewing the attempt summary, so the unit test will simply
452
     * create and trigger the event and ensure the event data is returned as expected.
453
     */
11 efrain 454
    public function test_attempt_summary_viewed(): void {
1 efrain 455
        $this->resetAfterTest();
456
 
457
        $this->setAdminUser();
458
        $course = $this->getDataGenerator()->create_course();
459
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
460
 
461
        $params = [
462
            'objectid' => 1,
463
            'relateduserid' => 2,
464
            'courseid' => $course->id,
465
            'context' => \context_module::instance($quiz->cmid),
466
            'other' => [
467
                'quizid' => $quiz->id
468
            ]
469
        ];
470
        $event = \mod_quiz\event\attempt_summary_viewed::create($params);
471
 
472
        // Trigger and capture the event.
473
        $sink = $this->redirectEvents();
474
        $event->trigger();
475
        $events = $sink->get_events();
476
        $event = reset($events);
477
 
478
        // Check that the event data is valid.
479
        $this->assertInstanceOf('\mod_quiz\event\attempt_summary_viewed', $event);
480
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
481
        $this->assertEventContextNotUsed($event);
482
    }
483
 
484
    /**
485
     * Test the user override created event.
486
     *
487
     * There is no external API for creating a user override, so the unit test will simply
488
     * create and trigger the event and ensure the event data is returned as expected.
489
     */
11 efrain 490
    public function test_user_override_created(): void {
1 efrain 491
        $this->resetAfterTest();
492
 
493
        $this->setAdminUser();
494
        $course = $this->getDataGenerator()->create_course();
495
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
496
 
497
        $params = [
498
            'objectid' => 1,
499
            'relateduserid' => 2,
500
            'context' => \context_module::instance($quiz->cmid),
501
            'other' => [
502
                'quizid' => $quiz->id
503
            ]
504
        ];
505
        $event = \mod_quiz\event\user_override_created::create($params);
506
 
507
        // Trigger and capture the event.
508
        $sink = $this->redirectEvents();
509
        $event->trigger();
510
        $events = $sink->get_events();
511
        $event = reset($events);
512
 
513
        // Check that the event data is valid.
514
        $this->assertInstanceOf('\mod_quiz\event\user_override_created', $event);
515
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
516
        $this->assertEventContextNotUsed($event);
517
    }
518
 
519
    /**
520
     * Test the group override created event.
521
     *
522
     * There is no external API for creating a group override, so the unit test will simply
523
     * create and trigger the event and ensure the event data is returned as expected.
524
     */
11 efrain 525
    public function test_group_override_created(): void {
1 efrain 526
        $this->resetAfterTest();
527
 
528
        $this->setAdminUser();
529
        $course = $this->getDataGenerator()->create_course();
530
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
531
 
532
        $params = [
533
            'objectid' => 1,
534
            'context' => \context_module::instance($quiz->cmid),
535
            'other' => [
536
                'quizid' => $quiz->id,
537
                'groupid' => 2
538
            ]
539
        ];
540
        $event = \mod_quiz\event\group_override_created::create($params);
541
 
542
        // Trigger and capture the event.
543
        $sink = $this->redirectEvents();
544
        $event->trigger();
545
        $events = $sink->get_events();
546
        $event = reset($events);
547
 
548
        // Check that the event data is valid.
549
        $this->assertInstanceOf('\mod_quiz\event\group_override_created', $event);
550
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
551
        $this->assertEventContextNotUsed($event);
552
    }
553
 
554
    /**
555
     * Test the user override updated event.
556
     *
557
     * There is no external API for updating a user override, so the unit test will simply
558
     * create and trigger the event and ensure the event data is returned as expected.
559
     */
11 efrain 560
    public function test_user_override_updated(): void {
1 efrain 561
        $this->resetAfterTest();
562
 
563
        $this->setAdminUser();
564
        $course = $this->getDataGenerator()->create_course();
565
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
566
 
567
        $params = [
568
            'objectid' => 1,
569
            'relateduserid' => 2,
570
            'context' => \context_module::instance($quiz->cmid),
571
            'other' => [
572
                'quizid' => $quiz->id
573
            ]
574
        ];
575
        $event = \mod_quiz\event\user_override_updated::create($params);
576
 
577
        // Trigger and capture the event.
578
        $sink = $this->redirectEvents();
579
        $event->trigger();
580
        $events = $sink->get_events();
581
        $event = reset($events);
582
 
583
        // Check that the event data is valid.
584
        $this->assertInstanceOf('\mod_quiz\event\user_override_updated', $event);
585
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
586
        $this->assertEventContextNotUsed($event);
587
    }
588
 
589
    /**
590
     * Test the group override updated event.
591
     *
592
     * There is no external API for updating a group override, so the unit test will simply
593
     * create and trigger the event and ensure the event data is returned as expected.
594
     */
11 efrain 595
    public function test_group_override_updated(): void {
1 efrain 596
        $this->resetAfterTest();
597
 
598
        $this->setAdminUser();
599
        $course = $this->getDataGenerator()->create_course();
600
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
601
 
602
        $params = [
603
            'objectid' => 1,
604
            'context' => \context_module::instance($quiz->cmid),
605
            'other' => [
606
                'quizid' => $quiz->id,
607
                'groupid' => 2
608
            ]
609
        ];
610
        $event = \mod_quiz\event\group_override_updated::create($params);
611
 
612
        // Trigger and capture the event.
613
        $sink = $this->redirectEvents();
614
        $event->trigger();
615
        $events = $sink->get_events();
616
        $event = reset($events);
617
 
618
        // Check that the event data is valid.
619
        $this->assertInstanceOf('\mod_quiz\event\group_override_updated', $event);
620
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
621
        $this->assertEventContextNotUsed($event);
622
    }
623
 
624
    /**
625
     * Test the user override deleted event.
626
     */
11 efrain 627
    public function test_user_override_deleted(): void {
1 efrain 628
        global $DB;
629
 
630
        $this->resetAfterTest();
631
 
632
        $this->setAdminUser();
633
        $course = $this->getDataGenerator()->create_course();
634
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
635
        $quizsettings = quiz_settings::create($quiz->id);
636
 
637
        // Create an override.
638
        $override = new \stdClass();
639
        $override->quiz = $quiz->id;
640
        $override->userid = 2;
641
        $override->id = $DB->insert_record('quiz_overrides', $override);
642
 
643
        // Trigger and capture the event.
644
        $sink = $this->redirectEvents();
645
        $quizsettings->get_override_manager()->delete_overrides(overrides: [$override]);
646
        $events = $sink->get_events();
647
        $event = reset($events);
648
 
649
        // Check that the event data is valid.
650
        $this->assertInstanceOf('\mod_quiz\event\user_override_deleted', $event);
651
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
652
        $this->assertEventContextNotUsed($event);
653
    }
654
 
655
    /**
656
     * Test the group override deleted event.
657
     */
11 efrain 658
    public function test_group_override_deleted(): void {
1 efrain 659
        global $DB;
660
 
661
        $this->resetAfterTest();
662
 
663
        $this->setAdminUser();
664
        $course = $this->getDataGenerator()->create_course();
665
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
666
        $quizsettings = quiz_settings::create($quiz->id);
667
 
668
        // Create an override.
669
        $override = new \stdClass();
670
        $override->quiz = $quiz->id;
671
        $override->groupid = 2;
672
        $override->id = $DB->insert_record('quiz_overrides', $override);
673
 
674
        // Trigger and capture the event.
675
        $sink = $this->redirectEvents();
676
        $quizsettings->get_override_manager()->delete_overrides(overrides: [$override]);
677
        $events = $sink->get_events();
678
        $event = reset($events);
679
 
680
        // Check that the event data is valid.
681
        $this->assertInstanceOf('\mod_quiz\event\group_override_deleted', $event);
682
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
683
        $this->assertEventContextNotUsed($event);
684
    }
685
 
686
    /**
687
     * Test the attempt viewed event.
688
     *
689
     * There is no external API for continuing an attempt, so the unit test will simply
690
     * create and trigger the event and ensure the event data is returned as expected.
691
     */
11 efrain 692
    public function test_attempt_viewed(): void {
1 efrain 693
        $this->resetAfterTest();
694
 
695
        $this->setAdminUser();
696
        $course = $this->getDataGenerator()->create_course();
697
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
698
 
699
        $params = [
700
            'objectid' => 1,
701
            'relateduserid' => 2,
702
            'courseid' => $course->id,
703
            'context' => \context_module::instance($quiz->cmid),
704
            'other' => [
705
                'quizid' => $quiz->id,
706
                'page' => 0
707
            ]
708
        ];
709
        $event = \mod_quiz\event\attempt_viewed::create($params);
710
 
711
        // Trigger and capture the event.
712
        $sink = $this->redirectEvents();
713
        $event->trigger();
714
        $events = $sink->get_events();
715
        $event = reset($events);
716
 
717
        // Check that the event data is valid.
718
        $this->assertInstanceOf('\mod_quiz\event\attempt_viewed', $event);
719
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
720
        $this->assertEventContextNotUsed($event);
721
    }
722
 
723
    /**
724
     * Test the attempt previewed event.
725
     */
11 efrain 726
    public function test_attempt_preview_started(): void {
1 efrain 727
        $quizobj = $this->prepare_quiz();
728
 
729
        $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
730
        $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
731
 
732
        $timenow = time();
733
        $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, true);
734
        quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
735
 
736
        // Trigger and capture the event.
737
        $sink = $this->redirectEvents();
738
        quiz_attempt_save_started($quizobj, $quba, $attempt);
739
        $events = $sink->get_events();
740
        $event = reset($events);
741
 
742
        // Check that the event data is valid.
743
        $this->assertInstanceOf('\mod_quiz\event\attempt_preview_started', $event);
744
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
745
        $this->assertEventContextNotUsed($event);
746
    }
747
 
748
    /**
749
     * Test the question manually graded event.
750
     *
751
     * There is no external API for manually grading a question, so the unit test will simply
752
     * create and trigger the event and ensure the event data is returned as expected.
753
     */
11 efrain 754
    public function test_question_manually_graded(): void {
1 efrain 755
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
756
 
757
        $params = [
758
            'objectid' => 1,
759
            'courseid' => $quizobj->get_courseid(),
760
            'context' => \context_module::instance($quizobj->get_cmid()),
761
            'other' => [
762
                'quizid' => $quizobj->get_quizid(),
763
                'attemptid' => 2,
764
                'slot' => 3
765
            ]
766
        ];
767
        $event = \mod_quiz\event\question_manually_graded::create($params);
768
 
769
        // Trigger and capture the event.
770
        $sink = $this->redirectEvents();
771
        $event->trigger();
772
        $events = $sink->get_events();
773
        $event = reset($events);
774
 
775
        // Check that the event data is valid.
776
        $this->assertInstanceOf('\mod_quiz\event\question_manually_graded', $event);
777
        $this->assertEquals(\context_module::instance($quizobj->get_cmid()), $event->get_context());
778
        $this->assertEventContextNotUsed($event);
779
    }
780
 
781
    /**
782
     * Test the attempt regraded event.
783
     *
784
     * There is no external API for regrading attempts, so the unit test will simply
785
     * create and trigger the event and ensure the event data is returned as expected.
786
     */
11 efrain 787
    public function test_attempt_regraded(): void {
1 efrain 788
        $this->resetAfterTest();
789
 
790
        $this->setAdminUser();
791
        $course = $this->getDataGenerator()->create_course();
792
        $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]);
793
 
794
        $params = [
795
            'objectid' => 1,
796
            'relateduserid' => 2,
797
            'courseid' => $course->id,
798
            'context' => \context_module::instance($quiz->cmid),
799
            'other' => [
800
                'quizid' => $quiz->id
801
            ]
802
        ];
803
        $event = \mod_quiz\event\attempt_regraded::create($params);
804
 
805
        // Trigger and capture the event.
806
        $sink = $this->redirectEvents();
807
        $event->trigger();
808
        $events = $sink->get_events();
809
        $event = reset($events);
810
 
811
        // Check that the event data is valid.
812
        $this->assertInstanceOf('\mod_quiz\event\attempt_regraded', $event);
813
        $this->assertEquals(\context_module::instance($quiz->cmid), $event->get_context());
814
        $this->assertEventContextNotUsed($event);
815
    }
816
 
817
    /**
818
     * Test the attempt notify manual graded event.
819
     * There is no external API for notification email when manual grading of user's attempt is completed,
820
     * so the unit test will simply create and trigger the event and ensure the event data is returned as expected.
821
     */
11 efrain 822
    public function test_attempt_manual_grading_completed(): void {
1 efrain 823
        $this->resetAfterTest();
824
        list($quizobj, $quba, $attempt) = $this->prepare_quiz_data();
825
        $attemptobj = quiz_attempt::create($attempt->id);
826
 
827
        $params = [
828
            'objectid' => $attemptobj->get_attemptid(),
829
            'relateduserid' => $attemptobj->get_userid(),
830
            'courseid' => $attemptobj->get_course()->id,
831
            'context' => \context_module::instance($attemptobj->get_cmid()),
832
            'other' => [
833
                'quizid' => $attemptobj->get_quizid()
834
            ]
835
        ];
836
        $event = \mod_quiz\event\attempt_manual_grading_completed::create($params);
837
 
838
        // Catch the event.
839
        $sink = $this->redirectEvents();
840
        $event->trigger();
841
        $events = $sink->get_events();
842
        $sink->close();
843
 
844
        // Validate the event.
845
        $this->assertCount(1, $events);
846
        $event = reset($events);
847
        $this->assertInstanceOf('\mod_quiz\event\attempt_manual_grading_completed', $event);
848
        $this->assertEquals('quiz_attempts', $event->objecttable);
849
        $this->assertEquals($quizobj->get_context(), $event->get_context());
850
        $this->assertEquals($attempt->userid, $event->relateduserid);
851
        $this->assertNotEmpty($event->get_description());
852
        $this->assertEventContextNotUsed($event);
853
    }
854
 
855
    /**
856
     * Test the page break created event.
857
     *
858
     * There is no external API for creating page break, so the unit test will simply
859
     * create and trigger the event and ensure the event data is returned as expected.
860
     */
11 efrain 861
    public function test_page_break_created(): void {
1 efrain 862
        $quizobj = $this->prepare_quiz();
863
 
864
        $params = [
865
            'objectid' => 1,
866
            'context' => context_module::instance($quizobj->get_cmid()),
867
            'other' => [
868
                'quizid' => $quizobj->get_quizid(),
869
                'slotnumber' => 3,
870
            ]
871
        ];
872
        $event = \mod_quiz\event\page_break_created::create($params);
873
 
874
        // Trigger and capture the event.
875
        $sink = $this->redirectEvents();
876
        $event->trigger();
877
        $events = $sink->get_events();
878
        $event = reset($events);
879
 
880
        // Check that the event data is valid.
881
        $this->assertInstanceOf('\mod_quiz\event\page_break_created', $event);
882
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
883
        $this->assertEventContextNotUsed($event);
884
    }
885
 
886
    /**
887
     * Test the page break deleted event.
888
     *
889
     * There is no external API for deleting page break, so the unit test will simply
890
     * create and trigger the event and ensure the event data is returned as expected.
891
     */
11 efrain 892
    public function test_page_deleted_created(): void {
1 efrain 893
        $quizobj = $this->prepare_quiz();
894
 
895
        $params = [
896
            'objectid' => 1,
897
            'context' => context_module::instance($quizobj->get_cmid()),
898
            'other' => [
899
                'quizid' => $quizobj->get_quizid(),
900
                'slotnumber' => 3,
901
            ]
902
        ];
903
        $event = \mod_quiz\event\page_break_deleted::create($params);
904
 
905
        // Trigger and capture the event.
906
        $sink = $this->redirectEvents();
907
        $event->trigger();
908
        $events = $sink->get_events();
909
        $event = reset($events);
910
 
911
        // Check that the event data is valid.
912
        $this->assertInstanceOf('\mod_quiz\event\page_break_deleted', $event);
913
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
914
        $this->assertEventContextNotUsed($event);
915
    }
916
 
917
    /**
918
     * Test the quiz grade updated event.
919
     *
920
     * There is no external API for updating quiz grade, so the unit test will simply
921
     * create and trigger the event and ensure the event data is returned as expected.
922
     */
11 efrain 923
    public function test_quiz_grade_updated(): void {
1 efrain 924
        $quizobj = $this->prepare_quiz();
925
 
926
        $params = [
927
            'objectid' => $quizobj->get_quizid(),
928
            'context' => context_module::instance($quizobj->get_cmid()),
929
            'other' => [
930
                'oldgrade' => 1,
931
                'newgrade' => 3,
932
            ]
933
        ];
934
        $event = \mod_quiz\event\quiz_grade_updated::create($params);
935
 
936
        // Trigger and capture the event.
937
        $sink = $this->redirectEvents();
938
        $event->trigger();
939
        $events = $sink->get_events();
940
        $event = reset($events);
941
 
942
        // Check that the event data is valid.
943
        $this->assertInstanceOf('\mod_quiz\event\quiz_grade_updated', $event);
944
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
945
        $this->assertEventContextNotUsed($event);
946
    }
947
 
948
    /**
949
     * Test the quiz re-paginated event.
950
     *
951
     * There is no external API for re-paginating quiz, so the unit test will simply
952
     * create and trigger the event and ensure the event data is returned as expected.
953
     */
11 efrain 954
    public function test_quiz_repaginated(): void {
1 efrain 955
        $quizobj = $this->prepare_quiz();
956
 
957
        $params = [
958
            'objectid' => $quizobj->get_quizid(),
959
            'context' => context_module::instance($quizobj->get_cmid()),
960
            'other' => [
961
                'slotsperpage' => 3,
962
            ]
963
        ];
964
        $event = \mod_quiz\event\quiz_repaginated::create($params);
965
 
966
        // Trigger and capture the event.
967
        $sink = $this->redirectEvents();
968
        $event->trigger();
969
        $events = $sink->get_events();
970
        $event = reset($events);
971
 
972
        // Check that the event data is valid.
973
        $this->assertInstanceOf('\mod_quiz\event\quiz_repaginated', $event);
974
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
975
        $this->assertEventContextNotUsed($event);
976
    }
977
 
978
    /**
979
     * Test the section break created event.
980
     *
981
     * There is no external API for creating section break, so the unit test will simply
982
     * create and trigger the event and ensure the event data is returned as expected.
983
     */
11 efrain 984
    public function test_section_break_created(): void {
1 efrain 985
        $quizobj = $this->prepare_quiz();
986
 
987
        $params = [
988
            'objectid' => 1,
989
            'context' => context_module::instance($quizobj->get_cmid()),
990
            'other' => [
991
                'quizid' => $quizobj->get_quizid(),
992
                'firstslotid' => 1,
993
                'firstslotnumber' => 2,
994
                'title' => 'New title'
995
            ]
996
        ];
997
        $event = \mod_quiz\event\section_break_created::create($params);
998
 
999
        // Trigger and capture the event.
1000
        $sink = $this->redirectEvents();
1001
        $event->trigger();
1002
        $events = $sink->get_events();
1003
        $event = reset($events);
1004
 
1005
        // Check that the event data is valid.
1006
        $this->assertInstanceOf('\mod_quiz\event\section_break_created', $event);
1007
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1008
        $this->assertStringContainsString($params['other']['title'], $event->get_description());
1009
        $this->assertEventContextNotUsed($event);
1010
    }
1011
 
1012
    /**
1013
     * Test the section break deleted event.
1014
     *
1015
     * There is no external API for deleting section break, so the unit test will simply
1016
     * create and trigger the event and ensure the event data is returned as expected.
1017
     */
11 efrain 1018
    public function test_section_break_deleted(): void {
1 efrain 1019
        $quizobj = $this->prepare_quiz();
1020
 
1021
        $params = [
1022
            'objectid' => 1,
1023
            'context' => context_module::instance($quizobj->get_cmid()),
1024
            'other' => [
1025
                'quizid' => $quizobj->get_quizid(),
1026
                'firstslotid' => 1,
1027
                'firstslotnumber' => 2
1028
            ]
1029
        ];
1030
        $event = \mod_quiz\event\section_break_deleted::create($params);
1031
 
1032
        // Trigger and capture the event.
1033
        $sink = $this->redirectEvents();
1034
        $event->trigger();
1035
        $events = $sink->get_events();
1036
        $event = reset($events);
1037
 
1038
        // Check that the event data is valid.
1039
        $this->assertInstanceOf('\mod_quiz\event\section_break_deleted', $event);
1040
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1041
        $this->assertEventContextNotUsed($event);
1042
    }
1043
 
1044
    /**
1045
     * Test the section shuffle updated event.
1046
     *
1047
     * There is no external API for updating section shuffle, so the unit test will simply
1048
     * create and trigger the event and ensure the event data is returned as expected.
1049
     */
11 efrain 1050
    public function test_section_shuffle_updated(): void {
1 efrain 1051
        $quizobj = $this->prepare_quiz();
1052
 
1053
        $params = [
1054
            'objectid' => 1,
1055
            'context' => context_module::instance($quizobj->get_cmid()),
1056
            'other' => [
1057
                'quizid' => $quizobj->get_quizid(),
1058
                'firstslotnumber' => 2,
1059
                'shuffle' => true
1060
            ]
1061
        ];
1062
        $event = \mod_quiz\event\section_shuffle_updated::create($params);
1063
 
1064
        // Trigger and capture the event.
1065
        $sink = $this->redirectEvents();
1066
        $event->trigger();
1067
        $events = $sink->get_events();
1068
        $event = reset($events);
1069
 
1070
        // Check that the event data is valid.
1071
        $this->assertInstanceOf('\mod_quiz\event\section_shuffle_updated', $event);
1072
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1073
        $this->assertEventContextNotUsed($event);
1074
    }
1075
 
1076
    /**
1077
     * Test the section title updated event.
1078
     *
1079
     * There is no external API for updating section title, so the unit test will simply
1080
     * create and trigger the event and ensure the event data is returned as expected.
1081
     */
11 efrain 1082
    public function test_section_title_updated(): void {
1 efrain 1083
        $quizobj = $this->prepare_quiz();
1084
 
1085
        $params = [
1086
            'objectid' => 1,
1087
            'context' => context_module::instance($quizobj->get_cmid()),
1088
            'other' => [
1089
                'quizid' => $quizobj->get_quizid(),
1090
                'firstslotid' => 1,
1091
                'firstslotnumber' => 2,
1092
                'newtitle' => 'New title'
1093
            ]
1094
        ];
1095
        $event = \mod_quiz\event\section_title_updated::create($params);
1096
 
1097
        // Trigger and capture the event.
1098
        $sink = $this->redirectEvents();
1099
        $event->trigger();
1100
        $events = $sink->get_events();
1101
        $event = reset($events);
1102
 
1103
        // Check that the event data is valid.
1104
        $this->assertInstanceOf('\mod_quiz\event\section_title_updated', $event);
1105
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1106
        $this->assertStringContainsString($params['other']['newtitle'], $event->get_description());
1107
        $this->assertEventContextNotUsed($event);
1108
    }
1109
 
1110
    /**
1111
     * Test the slot created event.
1112
     *
1113
     * There is no external API for creating slot, so the unit test will simply
1114
     * create and trigger the event and ensure the event data is returned as expected.
1115
     */
11 efrain 1116
    public function test_slot_created(): void {
1 efrain 1117
        $quizobj = $this->prepare_quiz();
1118
 
1119
        $params = [
1120
            'objectid' => 1,
1121
            'context' => context_module::instance($quizobj->get_cmid()),
1122
            'other' => [
1123
                'quizid' => $quizobj->get_quizid(),
1124
                'slotnumber' => 1,
1125
                'page' => 1
1126
            ]
1127
        ];
1128
        $event = \mod_quiz\event\slot_created::create($params);
1129
 
1130
        // Trigger and capture the event.
1131
        $sink = $this->redirectEvents();
1132
        $event->trigger();
1133
        $events = $sink->get_events();
1134
        $event = reset($events);
1135
 
1136
        // Check that the event data is valid.
1137
        $this->assertInstanceOf('\mod_quiz\event\slot_created', $event);
1138
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1139
        $this->assertEventContextNotUsed($event);
1140
    }
1141
 
1142
    /**
1143
     * Test the slot deleted event.
1144
     *
1145
     * There is no external API for deleting slot, so the unit test will simply
1146
     * create and trigger the event and ensure the event data is returned as expected.
1147
     */
11 efrain 1148
    public function test_slot_deleted(): void {
1 efrain 1149
        $quizobj = $this->prepare_quiz();
1150
 
1151
        $params = [
1152
            'objectid' => 1,
1153
            'context' => context_module::instance($quizobj->get_cmid()),
1154
            'other' => [
1155
                'quizid' => $quizobj->get_quizid(),
1156
                'slotnumber' => 1,
1157
            ]
1158
        ];
1159
        $event = \mod_quiz\event\slot_deleted::create($params);
1160
 
1161
        // Trigger and capture the event.
1162
        $sink = $this->redirectEvents();
1163
        $event->trigger();
1164
        $events = $sink->get_events();
1165
        $event = reset($events);
1166
 
1167
        // Check that the event data is valid.
1168
        $this->assertInstanceOf('\mod_quiz\event\slot_deleted', $event);
1169
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1170
        $this->assertEventContextNotUsed($event);
1171
    }
1172
 
1173
    /**
1174
     * Test the slot mark updated event.
1175
     *
1176
     * There is no external API for updating slot mark, so the unit test will simply
1177
     * create and trigger the event and ensure the event data is returned as expected.
1178
     */
11 efrain 1179
    public function test_slot_mark_updated(): void {
1 efrain 1180
        $quizobj = $this->prepare_quiz();
1181
 
1182
        $params = [
1183
            'objectid' => 1,
1184
            'context' => context_module::instance($quizobj->get_cmid()),
1185
            'other' => [
1186
                'quizid' => $quizobj->get_quizid(),
1187
                'previousmaxmark' => 1,
1188
                'newmaxmark' => 2,
1189
            ]
1190
        ];
1191
        $event = \mod_quiz\event\slot_mark_updated::create($params);
1192
 
1193
        // Trigger and capture the event.
1194
        $sink = $this->redirectEvents();
1195
        $event->trigger();
1196
        $events = $sink->get_events();
1197
        $event = reset($events);
1198
 
1199
        // Check that the event data is valid.
1200
        $this->assertInstanceOf('\mod_quiz\event\slot_mark_updated', $event);
1201
        $this->assertEquals($quizobj->get_context(), $event->get_context());
1202
        $this->assertEventContextNotUsed($event);
1203
    }
1204
 
1205
    /**
1206
     * Test quiz_grade_item_created.
1207
     *
1208
     * @covers \mod_quiz\event\quiz_grade_item_created
1209
     */
1210
    public function test_quiz_grade_item_created(): void {
1211
        global $USER;
1212
 
1213
        $quizobj = $this->prepare_quiz();
1214
        $stucture = $quizobj->get_structure();
1215
 
1216
        // Trigger and capture the event.
1217
        $sink = $this->redirectEvents();
1218
        $stucture->create_grade_item((object) ['quizid' => $quizobj->get_quizid(), 'name' => 'Test']);
1219
        $events = $sink->get_events();
1220
        /** @var slot_grade_item_updated $event */
1221
        $event = reset($events);
1222
 
1223
        // Check that the event data is valid.
1224
        $stucture = $quizobj->get_structure();
1225
        $gradeitem = array_values($stucture->get_grade_items())[0];
1226
        $this->assertInstanceOf(quiz_grade_item_created::class, $event);
1227
        $this->assertEquals($quizobj->get_context(), $event->get_context());
1228
        $this->assertEventContextNotUsed($event);
1229
        $this->assertEquals(new \moodle_url('/mod/quiz/editgrading.php', ['cmid' => $quizobj->get_cmid()]),
1230
            $event->get_url());
1231
        $this->assertEquals("The user with id '$USER->id' created quiz grade item with id '$gradeitem->id' " .
1232
            "for the quiz with course module id '{$quizobj->get_cmid()}'.",
1233
            $event->get_description());
1234
    }
1235
 
1236
    /**
1237
     * Test quiz_grade_item_updated.
1238
     *
1239
     * @covers \mod_quiz\event\quiz_grade_item_updated
1240
     */
1241
    public function test_quiz_grade_item_updated(): void {
1242
        global $USER;
1243
 
1244
        $quizobj = $this->prepare_quiz();
1245
        /** @var \mod_quiz_generator $quizgenerator */
1246
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
1247
        $gradeitem = $quizgenerator->create_grade_item(
1248
            ['quizid' => $quizobj->get_quizid(), 'name' => 'Awesomeness!']);
1249
        $stucture = $quizobj->get_structure();
1250
 
1251
        // Trigger and capture the event.
1252
        $sink = $this->redirectEvents();
1253
        $stucture->update_grade_item((object) ['id' => $gradeitem->id, 'name' => 'Test']);
1254
        $events = $sink->get_events();
1255
        /** @var slot_grade_item_updated $event */
1256
        $event = reset($events);
1257
 
1258
        // Check that the event data is valid.
1259
        $this->assertInstanceOf(quiz_grade_item_updated::class, $event);
1260
        $this->assertEquals($quizobj->get_context(), $event->get_context());
1261
        $this->assertEventContextNotUsed($event);
1262
        $this->assertEquals(new \moodle_url('/mod/quiz/editgrading.php', ['cmid' => $quizobj->get_cmid()]),
1263
            $event->get_url());
1264
        $this->assertEquals("The user with id '$USER->id' updated quiz grade item with id '$gradeitem->id' " .
1265
            "for the quiz with course module id '{$quizobj->get_cmid()}'.",
1266
            $event->get_description());
1267
    }
1268
 
1269
    /**
1270
     * Test quiz_grade_item_deleted.
1271
     *
1272
     * @covers \mod_quiz\event\quiz_grade_item_deleted
1273
     */
1274
    public function test_quiz_grade_item_deleted(): void {
1275
        global $USER;
1276
 
1277
        $quizobj = $this->prepare_quiz();
1278
        /** @var \mod_quiz_generator $quizgenerator */
1279
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
1280
        $gradeitem = $quizgenerator->create_grade_item(
1281
            ['quizid' => $quizobj->get_quizid(), 'name' => 'Awesomeness!']);
1282
        $stucture = $quizobj->get_structure();
1283
 
1284
        // Trigger and capture the event.
1285
        $sink = $this->redirectEvents();
1286
        $stucture->delete_grade_item($gradeitem->id);
1287
        $events = $sink->get_events();
1288
        /** @var slot_grade_item_updated $event */
1289
        $event = reset($events);
1290
 
1291
        // Check that the event data is valid.
1292
        $this->assertInstanceOf(quiz_grade_item_deleted::class, $event);
1293
        $this->assertEquals($quizobj->get_context(), $event->get_context());
1294
        $this->assertEventContextNotUsed($event);
1295
        $this->assertEquals(new \moodle_url('/mod/quiz/editgrading.php', ['cmid' => $quizobj->get_cmid()]),
1296
            $event->get_url());
1297
        $this->assertEquals("The user with id '$USER->id' deleted quiz grade item with id '$gradeitem->id' " .
1298
            "for the quiz with course module id '{$quizobj->get_cmid()}'.",
1299
            $event->get_description());
1300
    }
1301
 
1302
    /**
1303
     * Test slot_grade_item_updated.
1304
     *
1305
     * @covers \mod_quiz\event\slot_grade_item_updated
1306
     */
1307
    public function test_slot_grade_item_updated(): void {
1308
        global $USER;
1309
 
1310
        $quizobj = $this->prepare_quiz();
1311
        /** @var \mod_quiz_generator $quizgenerator */
1312
        $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
1313
        $gradeitem = $quizgenerator->create_grade_item(
1314
            ['quizid' => $quizobj->get_quizid(), 'name' => 'Awesomeness!']);
1315
        $stucture = $quizobj->get_structure();
1316
        $slot = $stucture->get_slot_by_number(1);
1317
 
1318
        // Trigger and capture the event.
1319
        $sink = $this->redirectEvents();
1320
        $stucture->update_slot_grade_item($slot, $gradeitem->id);
1321
        $events = $sink->get_events();
1322
        /** @var slot_grade_item_updated $event */
1323
        $event = reset($events);
1324
 
1325
        // Check that the event data is valid.
1326
        $this->assertInstanceOf(slot_grade_item_updated::class, $event);
1327
        $this->assertEquals($quizobj->get_context(), $event->get_context());
1328
        $this->assertEventContextNotUsed($event);
1329
        $this->assertEquals(new \moodle_url('/mod/quiz/editgrading.php', ['cmid' => $quizobj->get_cmid()]),
1330
            $event->get_url());
1331
        $this->assertEquals("The user with id '$USER->id' updated the slot with id '{$slot->id}' " .
1332
            "belonging to the quiz with course module id '{$quizobj->get_cmid()}'. " .
1333
            "The grade item this slot contributes to was changed from '' to '$gradeitem->id'.",
1334
            $event->get_description());
1335
 
1336
        // Check nothing logged if the value is not changed.
1337
        $sink = $this->redirectEvents();
1338
        $stucture->update_slot_grade_item($slot, $gradeitem->id);
1339
        $events = $sink->get_events();
1340
        $this->assertCount(0, $events);
1341
    }
1342
 
1343
    /**
1344
     * Test the slot moved event.
1345
     *
1346
     * There is no external API for moving slot, so the unit test will simply
1347
     * create and trigger the event and ensure the event data is returned as expected.
1348
     */
11 efrain 1349
    public function test_slot_moved(): void {
1 efrain 1350
        $quizobj = $this->prepare_quiz();
1351
 
1352
        $params = [
1353
            'objectid' => 1,
1354
            'context' => context_module::instance($quizobj->get_cmid()),
1355
            'other' => [
1356
                'quizid' => $quizobj->get_quizid(),
1357
                'previousslotnumber' => 1,
1358
                'afterslotnumber' => 2,
1359
                'page' => 1
1360
            ]
1361
        ];
1362
        $event = \mod_quiz\event\slot_moved::create($params);
1363
 
1364
        // Trigger and capture the event.
1365
        $sink = $this->redirectEvents();
1366
        $event->trigger();
1367
        $events = $sink->get_events();
1368
        $event = reset($events);
1369
 
1370
        // Check that the event data is valid.
1371
        $this->assertInstanceOf('\mod_quiz\event\slot_moved', $event);
1372
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1373
        $this->assertEventContextNotUsed($event);
1374
    }
1375
 
1376
    /**
1377
     * Test the slot require previous updated event.
1378
     *
1379
     * There is no external API for updating slot require previous option, so the unit test will simply
1380
     * create and trigger the event and ensure the event data is returned as expected.
1381
     */
11 efrain 1382
    public function test_slot_requireprevious_updated(): void {
1 efrain 1383
        $quizobj = $this->prepare_quiz();
1384
 
1385
        $params = [
1386
            'objectid' => 1,
1387
            'context' => context_module::instance($quizobj->get_cmid()),
1388
            'other' => [
1389
                'quizid' => $quizobj->get_quizid(),
1390
                'requireprevious' => true
1391
            ]
1392
        ];
1393
        $event = \mod_quiz\event\slot_requireprevious_updated::create($params);
1394
 
1395
        // Trigger and capture the event.
1396
        $sink = $this->redirectEvents();
1397
        $event->trigger();
1398
        $events = $sink->get_events();
1399
        $event = reset($events);
1400
 
1401
        // Check that the event data is valid.
1402
        $this->assertInstanceOf('\mod_quiz\event\slot_requireprevious_updated', $event);
1403
        $this->assertEquals(context_module::instance($quizobj->get_cmid()), $event->get_context());
1404
        $this->assertEventContextNotUsed($event);
1405
    }
1406
}