MDL-68619 mod_h5pactivity: add activity check to get_attempt method
[moodle.git] / mod / h5pactivity / tests / local / manager_test.php
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/>.
17 /**
18  * mod_h5pactivity manager tests
19  *
20  * @package    mod_h5pactivity
21  * @category   test
22  * @copyright  2020 Ferran Recio <ferran@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 namespace mod_h5pactivity\local;
27 use context_module;
28 use stdClass;
30 /**
31  * Manager tests class for mod_h5pactivity.
32  *
33  * @package    mod_h5pactivity
34  * @category   test
35  * @copyright  2020 Ferran Recio <ferran@moodle.com>
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class manager_testcase extends \advanced_testcase {
40     /**
41      * Test for static create methods.
42      */
43     public function test_create() {
45         $this->resetAfterTest();
46         $this->setAdminUser();
48         $course = $this->getDataGenerator()->create_course();
49         $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
50         $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST);
51         $context = context_module::instance($cm->id);
53         $manager = manager::create_from_instance($activity);
54         $manageractivity = $manager->get_instance();
55         $this->assertEquals($activity->id, $manageractivity->id);
56         $managercm = $manager->get_coursemodule();
57         $this->assertEquals($cm->id, $managercm->id);
58         $managercontext = $manager->get_context();
59         $this->assertEquals($context->id, $managercontext->id);
61         $manager = manager::create_from_coursemodule($cm);
62         $manageractivity = $manager->get_instance();
63         $this->assertEquals($activity->id, $manageractivity->id);
64         $managercm = $manager->get_coursemodule();
65         $this->assertEquals($cm->id, $managercm->id);
66         $managercontext = $manager->get_context();
67         $this->assertEquals($context->id, $managercontext->id);
68     }
70     /**
71      * Test for is_tracking_enabled.
72      *
73      * @dataProvider is_tracking_enabled_data
74      * @param bool $login if the user is logged in
75      * @param string $role user role in course
76      * @param int $enabletracking if tracking is enabled
77      * @param bool $expected expected result
78      */
79     public function test_is_tracking_enabled(bool $login, string $role, int $enabletracking, bool $expected) {
81         $this->resetAfterTest();
82         $this->setAdminUser();
84         $course = $this->getDataGenerator()->create_course();
85         $activity = $this->getDataGenerator()->create_module('h5pactivity',
86                 ['course' => $course, 'enabletracking' => $enabletracking]);
88         $user = $this->getDataGenerator()->create_and_enrol($course, $role);
89         if ($login) {
90             $this->setUser($user);
91             $param = null;
92         } else {
93             $param = $user;
94         }
96         $manager = manager::create_from_instance($activity);
97         $this->assertEquals($expected, $manager->is_tracking_enabled($param));
98     }
100     /**
101      * Data provider for is_tracking_enabled.
102      *
103      * @return array
104      */
105     public function is_tracking_enabled_data(): array {
106         return [
107             'Logged student, tracking enabled' => [
108                 true, 'student', 1, true
109             ],
110             'Logged student, tracking disabled' => [
111                 true, 'student', 0, false
112             ],
113             'Logged teacher, tracking enabled' => [
114                 true, 'editingteacher', 1, false
115             ],
116             'Logged teacher, tracking disabled' => [
117                 true, 'editingteacher', 0, false
118             ],
119             'No logged student, tracking enabled' => [
120                 true, 'student', 1, true
121             ],
122             'No logged student, tracking disabled' => [
123                 true, 'student', 0, false
124             ],
125             'No logged teacher, tracking enabled' => [
126                 true, 'editingteacher', 1, false
127             ],
128             'No logged teacher, tracking disabled' => [
129                 true, 'editingteacher', 0, false
130             ],
131         ];
132     }
134     /**
135      * Test for get_users_scaled_score.
136      *
137      * @dataProvider get_users_scaled_score_data
138      * @param int $enabletracking if tracking is enabled
139      * @param int $gradingmethod new grading method
140      * @param array $result1 student 1 results (scaled, timemodified, attempt number)
141      * @param array $result2 student 2 results (scaled, timemodified, attempt number)
142      */
143     public function test_get_users_scaled_score(int $enabletracking, int $gradingmethod, array $result1, array $result2) {
144         global $DB;
146         $this->resetAfterTest();
147         $this->setAdminUser();
149         $course = $this->getDataGenerator()->create_course();
150         $activity = $this->getDataGenerator()->create_module('h5pactivity',
151                 ['course' => $course, 'enabletracking' => $enabletracking, 'grademethod' => $gradingmethod]);
153         // Generate two users with 4 attempts each.
154         $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
155         $this->generate_fake_attempts($activity, $user1, 1);
156         $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
157         $this->generate_fake_attempts($activity, $user2, 2);
159         $manager = manager::create_from_instance($activity);
161         // Get all users scaled scores.
162         $scaleds = $manager->get_users_scaled_score();
164         // No results will be returned if tracking is dsabled or manual grading method is defined.
165         if (empty($result1)) {
166             $this->assertNull($scaleds);
167             return;
168         }
170         $this->assertCount(2, $scaleds);
172         // Check expected user1 scaled score.
173         $scaled = $scaleds[$user1->id];
174         $this->assertEquals($user1->id, $scaled->userid);
175         $this->assertEquals($result1[0], $scaled->scaled);
176         $this->assertEquals($result1[1], $scaled->timemodified);
177         if ($result1[2]) {
178             $attempt = $DB->get_record('h5pactivity_attempts', ['id' => $scaled->attemptid]);
179             $this->assertEquals($attempt->h5pactivityid, $activity->id);
180             $this->assertEquals($attempt->userid, $scaled->userid);
181             $this->assertEquals($attempt->scaled, round($scaled->scaled, 5));
182             $this->assertEquals($attempt->timemodified, $scaled->timemodified);
183             $this->assertEquals($result1[2], $attempt->attempt);
184         } else {
185             $this->assertEquals(0, $scaled->attemptid);
186         }
188         // Check expected user2 scaled score.
189         $scaled = $scaleds[$user2->id];
190         $this->assertEquals($user2->id, $scaled->userid);
191         $this->assertEquals($result2[0], round($scaled->scaled, 5));
192         $this->assertEquals($result2[1], $scaled->timemodified);
193         if ($result2[2]) {
194             $attempt = $DB->get_record('h5pactivity_attempts', ['id' => $scaled->attemptid]);
195             $this->assertEquals($attempt->h5pactivityid, $activity->id);
196             $this->assertEquals($attempt->userid, $scaled->userid);
197             $this->assertEquals($attempt->scaled, $scaled->scaled);
198             $this->assertEquals($attempt->timemodified, $scaled->timemodified);
199             $this->assertEquals($result2[2], $attempt->attempt);
200         } else {
201             $this->assertEquals(0, $scaled->attemptid);
202         }
204         // Now check a single user record.
205         $scaleds = $manager->get_users_scaled_score($user2->id);
206         $this->assertCount(1, $scaleds);
207         $scaled2 = $scaleds[$user2->id];
208         $this->assertEquals($scaled->userid, $scaled2->userid);
209         $this->assertEquals($scaled->scaled, $scaled2->scaled);
210         $this->assertEquals($scaled->attemptid, $scaled2->attemptid);
211         $this->assertEquals($scaled->timemodified, $scaled2->timemodified);
212     }
214     /**
215      * Data provider for get_users_scaled_score.
216      *
217      * @return array
218      */
219     public function get_users_scaled_score_data(): array {
220         return [
221             'Tracking with max attempt method' => [
222                 1, manager::GRADEHIGHESTATTEMPT, [1.00000, 31, 2], [0.66667, 32, 2]
223             ],
224             'Tracking with average attempt method' => [
225                 1, manager::GRADEAVERAGEATTEMPT, [0.61111, 51, 0], [0.52222, 52, 0]
226             ],
227             'Tracking with last attempt method' => [
228                 1, manager::GRADELASTATTEMPT, [0.33333, 51, 3], [0.40000, 52, 3]
229             ],
230             'Tracking with first attempt method' => [
231                 1, manager::GRADEFIRSTATTEMPT, [0.50000, 11, 1], [0.50000, 12, 1]
232             ],
233             'Tracking with manual attempt grading' => [
234                 1, manager::GRADEMANUAL, [], []
235             ],
236             'No tracking with max attempt method' => [
237                 0, manager::GRADEHIGHESTATTEMPT, [], []
238             ],
239             'No tracking with average attempt method' => [
240                 0, manager::GRADEAVERAGEATTEMPT, [], []
241             ],
242             'No tracking with last attempt method' => [
243                 0, manager::GRADELASTATTEMPT, [], []
244             ],
245             'No tracking with first attempt method' => [
246                 0, manager::GRADEFIRSTATTEMPT, [], []
247             ],
248             'No tracking with manual attempt grading' => [
249                 0, manager::GRADEMANUAL, [], []
250             ],
251         ];
252     }
254     /**
255      * Test static get_grading_methods.
256      */
257     public function test_get_grading_methods() {
258         $methods = manager::get_grading_methods();
259         $this->assertCount(5, $methods);
260         $this->assertNotEmpty($methods[manager::GRADEHIGHESTATTEMPT]);
261         $this->assertNotEmpty($methods[manager::GRADEAVERAGEATTEMPT]);
262         $this->assertNotEmpty($methods[manager::GRADELASTATTEMPT]);
263         $this->assertNotEmpty($methods[manager::GRADEFIRSTATTEMPT]);
264         $this->assertNotEmpty($methods[manager::GRADEMANUAL]);
265     }
267     /**
268      * Test static get_selected_attempt.
269      *
270      * @dataProvider get_selected_attempt_data
271      * @param int $enabletracking if tracking is enabled
272      * @param int $gradingmethod new grading method
273      * @param int $result the expected result
274      */
275     public function test_get_selected_attempt(int $enabletracking, int $gradingmethod, int $result) {
276         $this->resetAfterTest();
277         $this->setAdminUser();
279         $course = $this->getDataGenerator()->create_course();
280         $activity = $this->getDataGenerator()->create_module('h5pactivity',
281                 ['course' => $course, 'enabletracking' => $enabletracking, 'grademethod' => $gradingmethod]);
283         $manager = manager::create_from_instance($activity);
285         $selected = $manager->get_selected_attempt();
287         $this->assertEquals($result, $selected[0]);
288         $this->assertNotEmpty($selected[1]);
289     }
291     /**
292      * Data provider for get_users_scaled_score.
293      *
294      * @return array
295      */
296     public function get_selected_attempt_data(): array {
297         return [
298             'Tracking with max attempt method' => [
299                 1, manager::GRADEHIGHESTATTEMPT, manager::GRADEHIGHESTATTEMPT
300             ],
301             'Tracking with average attempt method' => [
302                 1, manager::GRADEAVERAGEATTEMPT, manager::GRADEAVERAGEATTEMPT
303             ],
304             'Tracking with last attempt method' => [
305                 1, manager::GRADELASTATTEMPT, manager::GRADELASTATTEMPT
306             ],
307             'Tracking with first attempt method' => [
308                 1, manager::GRADEFIRSTATTEMPT, manager::GRADEFIRSTATTEMPT
309             ],
310             'Tracking with manual attempt grading' => [
311                 1, manager::GRADEMANUAL, manager::GRADEMANUAL
312             ],
313             'No tracking with max attempt method' => [
314                 0, manager::GRADEHIGHESTATTEMPT, manager::GRADEMANUAL
315             ],
316             'No tracking with average attempt method' => [
317                 0, manager::GRADEAVERAGEATTEMPT, manager::GRADEMANUAL
318             ],
319             'No tracking with last attempt method' => [
320                 0, manager::GRADELASTATTEMPT, manager::GRADEMANUAL
321             ],
322             'No tracking with first attempt method' => [
323                 0, manager::GRADEFIRSTATTEMPT, manager::GRADEMANUAL
324             ],
325             'No tracking with manual attempt grading' => [
326                 0, manager::GRADEMANUAL, manager::GRADEMANUAL
327             ],
328         ];
329     }
331     /**
332      * Test static get_review_modes.
333      */
334     public function test_get_review_modes() {
335         $methods = manager::get_review_modes();
336         $this->assertCount(2, $methods);
337         $this->assertNotEmpty($methods[manager::REVIEWCOMPLETION]);
338         $this->assertNotEmpty($methods[manager::REVIEWNONE]);
339     }
341     /**
342      * Test get_grader method.
343      */
344     public function test_get_grader() {
345         $this->resetAfterTest();
346         $this->setAdminUser();
348         $course = $this->getDataGenerator()->create_course();
349         $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
350         $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST);
351         $context = context_module::instance($cm->id);
353         $manager = manager::create_from_instance($activity);
354         $grader = $manager->get_grader();
356         $this->assertInstanceOf('mod_h5pactivity\local\grader', $grader);
357     }
360     /**
361      * Test static can_view_all_attempts.
362      *
363      * @dataProvider can_view_all_attempts_data
364      * @param int $enabletracking if tracking is enabled
365      * @param bool $usestudent if test must be done with a user role
366      * @param bool $useloggedin if test must be done with the loggedin user
367      * @param bool $result the expected result
368      */
369     public function test_can_view_all_attempts(int $enabletracking, bool $usestudent, bool $useloggedin, bool $result) {
370         global $USER;
372         $this->resetAfterTest();
373         $this->setAdminUser();
375         $course = $this->getDataGenerator()->create_course();
376         $activity = $this->getDataGenerator()->create_module('h5pactivity',
377                 ['course' => $course, 'enabletracking' => $enabletracking]);
379         $manager = manager::create_from_instance($activity);
381         $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
382         $loggedin = $USER;
384         // We want to test what when the method is called to check a different user than $USER.
385         if (!$usestudent) {
386             $loggedin = $user;
387             $user = $USER;
388         }
390         if ($useloggedin) {
391             $this->setUser($user);
392             $user = null;
393         } else {
394             $this->setUser($loggedin);
395         }
397         $this->assertEquals($result, $manager->can_view_all_attempts($user));
398     }
400     /**
401      * Data provider for test_can_view_all_attempts.
402      *
403      * @return array
404      */
405     public function can_view_all_attempts_data(): array {
406         return [
407             // No tracking cases.
408             'No tracking with admin using $USER' => [
409                 0, false, false, false
410             ],
411             'No tracking with student using $USER' => [
412                 0, true, false, false
413             ],
414             'No tracking with admin loggedin' => [
415                 0, false, true, false
416             ],
417             'No tracking with student loggedin' => [
418                 0, true, true, false
419             ],
420             // Tracking enabled cases.
421             'Tracking with admin using $USER' => [
422                 1, false, false, true
423             ],
424             'Tracking with student using $USER' => [
425                 1, true, false, false
426             ],
427             'Tracking with admin loggedin' => [
428                 1, false, true, true
429             ],
430             'Tracking with student loggedin' => [
431                 1, true, true, false
432             ],
433         ];
434     }
436     /**
437      * Test static can_view_own_attempts.
438      *
439      * @dataProvider can_view_own_attempts_data
440      * @param int $enabletracking if tracking is enabled
441      * @param int $reviewmode the attempt review mode
442      * @param bool $useloggedin if test must be done with the loggedin user
443      * @param bool $hasattempts if the student have attempts
444      * @param bool $result the expected result
445      */
446     public function test_can_view_own_attempts(int $enabletracking, int $reviewmode,
447             bool $useloggedin, bool $hasattempts, bool $result) {
449         $this->resetAfterTest();
450         $this->setAdminUser();
452         $course = $this->getDataGenerator()->create_course();
453         $activity = $this->getDataGenerator()->create_module('h5pactivity',
454                 ['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
456         $manager = manager::create_from_instance($activity);
458         $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
460         if ($hasattempts) {
461             $this->generate_fake_attempts($activity, $user, 1);
462         }
464         if ($useloggedin) {
465             $this->setUser($user);
466             $user = null;
467         }
469         $this->assertEquals($result, $manager->can_view_own_attempts($user));
470     }
472     /**
473      * Data provider for test_can_view_own_attempts.
474      *
475      * @return array
476      */
477     public function can_view_own_attempts_data(): array {
478         return [
479             // No tracking cases.
480             'No tracking, review none, using $USER, without attempts' => [
481                 0, manager::REVIEWNONE, false, false, false
482             ],
483             'No tracking, review enabled, using $USER, without attempts' => [
484                 0, manager::REVIEWCOMPLETION, false, false, false
485             ],
486             'No tracking, review none, loggedin, without attempts' => [
487                 0, manager::REVIEWNONE, true, false, false
488             ],
489             'No tracking, review enabled, loggedin, without attempts' => [
490                 0, manager::REVIEWCOMPLETION, true, false, false
491             ],
492             'No tracking, review none, using $USER, with attempts' => [
493                 0, manager::REVIEWNONE, false, true, false
494             ],
495             'No tracking, review enabled, using $USER, with attempts' => [
496                 0, manager::REVIEWCOMPLETION, false, true, false
497             ],
498             'No tracking, review none, loggedin, with attempts' => [
499                 0, manager::REVIEWNONE, true, true, false
500             ],
501             'No tracking, review enabled, loggedin, with attempts' => [
502                 0, manager::REVIEWCOMPLETION, true, true, false
503             ],
504             // Tracking enabled cases.
505             'Tracking enabled, review none, using $USER, without attempts' => [
506                 1, manager::REVIEWNONE, false, false, false
507             ],
508             'Tracking enabled, review enabled, using $USER, without attempts' => [
509                 1, manager::REVIEWCOMPLETION, false, false, true
510             ],
511             'Tracking enabled, review none, loggedin, without attempts' => [
512                 1, manager::REVIEWNONE, true, false, false
513             ],
514             'Tracking enabled, review enabled, loggedin, without attempts' => [
515                 1, manager::REVIEWCOMPLETION, true, false, true
516             ],
517             'Tracking enabled, review none, using $USER, with attempts' => [
518                 1, manager::REVIEWNONE, false, true, false
519             ],
520             'Tracking enabled, review enabled, using $USER, with attempts' => [
521                 1, manager::REVIEWCOMPLETION, false, true, true
522             ],
523             'Tracking enabled, review none, loggedin, with attempts' => [
524                 1, manager::REVIEWNONE, true, true, false
525             ],
526             'Tracking enabled, review enabled, loggedin, with attempts' => [
527                 1, manager::REVIEWCOMPLETION, true, true, true
528             ],
529         ];
530     }
532     /**
533      * Test static count_attempts.
534      */
535     public function test_count_attempts() {
537         $this->resetAfterTest();
538         $this->setAdminUser();
540         $course = $this->getDataGenerator()->create_course();
541         $activity = $this->getDataGenerator()->create_module('h5pactivity',
542                 ['course' => $course]);
544         $manager = manager::create_from_instance($activity);
546         // User without attempts.
547         $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
549         // User with 1 attempt.
550         $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
551         $this->generate_fake_attempts($activity, $user2, 1);
553         // User with 2 attempts.
554         $user3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
555         $this->generate_fake_attempts($activity, $user3, 1);
557         // Incomplete user2 and 3 has only 3 attempts completed.
558         $this->assertEquals(0, $manager->count_attempts($user1->id));
559         $this->assertEquals(3, $manager->count_attempts($user2->id));
560         $this->assertEquals(3, $manager->count_attempts($user3->id));
561     }
563     /**
564      * Test static count_attempts.
565      */
566     public function test_count_users_attempts() {
568         $this->resetAfterTest();
569         $this->setAdminUser();
571         $course = $this->getDataGenerator()->create_course();
572         $activity = $this->getDataGenerator()->create_module('h5pactivity',
573                 ['course' => $course]);
575         $manager = manager::create_from_instance($activity);
577         // User without attempts.
578         $user1 = $this->getDataGenerator()->create_and_enrol($course, 'student');
580         // User with 1 attempt.
581         $user2 = $this->getDataGenerator()->create_and_enrol($course, 'student');
582         $this->generate_fake_attempts($activity, $user2, 1);
584         // User with 2 attempts.
585         $user3 = $this->getDataGenerator()->create_and_enrol($course, 'student');
586         $this->generate_fake_attempts($activity, $user3, 1);
588         $attempts = $manager->count_users_attempts();
589         $this->assertArrayNotHasKey($user1->id, $attempts);
590         $this->assertArrayHasKey($user2->id, $attempts);
591         $this->assertEquals(4, $attempts[$user2->id]);
592         $this->assertArrayHasKey($user3->id, $attempts);
593         $this->assertEquals(4, $attempts[$user3->id]);
594     }
596     /**
597      * Test static get_report.
598      *
599      * @dataProvider get_report_data
600      * @param int $enabletracking if tracking is enabled
601      * @param int $reviewmode the attempt review mode
602      * @param bool $createattempts if the student have attempts
603      * @param string $role the user role (student or editingteacher)
604      * @param array $results the expected classname (or null)
605      */
606     public function test_get_report(int $enabletracking, int $reviewmode, bool $createattempts,
607             string $role, array $results) {
609         $this->resetAfterTest();
610         $this->setAdminUser();
612         $course = $this->getDataGenerator()->create_course();
613         $activity = $this->getDataGenerator()->create_module('h5pactivity',
614                 ['course' => $course, 'enabletracking' => $enabletracking, 'reviewmode' => $reviewmode]);
616         $manager = manager::create_from_instance($activity);
617         $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST);
619         $users = [
620             'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
621             'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
622             'otheruser' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
623         ];
625         $attempts = [];
626         if ($createattempts) {
627             $this->generate_fake_attempts($activity, $users['student'], 1);
628             $this->generate_fake_attempts($activity, $users['otheruser'], 2);
629             $attempts['student'] = attempt::last_attempt($users['student'], $cm);
630             $attempts['otheruser'] = attempt::last_attempt($users['otheruser'], $cm);
631         }
633         $classnamebase = 'mod_h5pactivity\\local\\report\\';
635         $attemptid = null;
636         if (isset($attempts['student'])) {
637             $attemptid = $attempts['student']->get_id() ?? null;
638         }
639         $userid = $users['student']->id;
641         // Check reports.
642         $this->setUser($users[$role]);
644         $report = $manager->get_report(null, null);
645         if ($results[0] === null) {
646             $this->assertNull($report);
647         } else {
648             $this->assertEquals($classnamebase.$results[0], get_class($report));
649         }
651         $report = $manager->get_report($userid, null);
652         if ($results[1] === null) {
653             $this->assertNull($report);
654         } else {
655             $this->assertEquals($classnamebase.$results[1], get_class($report));
656         }
658         $report = $manager->get_report($userid, $attemptid);
659         if ($results[2] === null) {
660             $this->assertNull($report);
661         } else {
662             $this->assertEquals($classnamebase.$results[2], get_class($report));
663         }
665         // Check that student cannot access another student reports.
666         if ($role == 'student') {
667             $attemptid = null;
668             if (isset($attempts['otheruser'])) {
669                 $attemptid = $attempts['otheruser']->get_id() ?? null;
670             }
671             $userid = $users['otheruser']->id;
673             $report = $manager->get_report($userid, null);
674             $this->assertNull($report);
676             $report = $manager->get_report($userid, $attemptid);
677             $this->assertNull($report);
678         }
679     }
681     /**
682      * Data provider for test_get_report.
683      *
684      * @return array
685      */
686     public function get_report_data(): array {
687         return [
688             // No tracking scenarios.
689             'No tracking, review none, no attempts, teacher' => [
690                 0, manager::REVIEWNONE, false, 'editingteacher', [null, null, null]
691             ],
692             'No tracking, review own, no attempts, teacher' => [
693                 0, manager::REVIEWCOMPLETION, false, 'editingteacher', [null, null, null]
694             ],
695             'No tracking, review none, no attempts, student' => [
696                 0, manager::REVIEWNONE, false, 'student', [null, null, null]
697             ],
698             'No tracking, review own, no attempts, student' => [
699                 0, manager::REVIEWCOMPLETION, false, 'student', [null, null, null]
700             ],
701             'No tracking, review none, with attempts, teacher' => [
702                 0, manager::REVIEWNONE, true, 'editingteacher', [null, null, null]
703             ],
704             'No tracking, review own, with attempts, teacher' => [
705                 0, manager::REVIEWCOMPLETION, true, 'editingteacher', [null, null, null]
706             ],
707             'No tracking, review none, with attempts, student' => [
708                 0, manager::REVIEWNONE, true, 'student', [null, null, null]
709             ],
710             'No tracking, review own, with attempts, student' => [
711                 0, manager::REVIEWCOMPLETION, true, 'student', [null, null, null]
712             ],
713             // Tracking enabled scenarios.
714             'Tracking enabled, review none, no attempts, teacher' => [
715                 1, manager::REVIEWNONE, false, 'editingteacher', ['participants', 'attempts', 'attempts']
716             ],
717             'Tracking enabled, review own, no attempts, teacher' => [
718                 1, manager::REVIEWCOMPLETION, false, 'editingteacher', ['participants', 'attempts', 'attempts']
719             ],
720             'Tracking enabled, review none, no attempts, student' => [
721                 1, manager::REVIEWNONE, false, 'student', [null, null, null]
722             ],
723             'Tracking enabled, review own, no attempts, student' => [
724                 1, manager::REVIEWCOMPLETION, false, 'student', ['attempts', 'attempts', 'attempts']
725             ],
726             'Tracking enabled, review none, with attempts, teacher' => [
727                 1, manager::REVIEWNONE, true, 'editingteacher', ['participants', 'attempts', 'results']
728             ],
729             'Tracking enabled, review own, with attempts, teacher' => [
730                 1, manager::REVIEWCOMPLETION, true, 'editingteacher', ['participants', 'attempts', 'results']
731             ],
732             'Tracking enabled, review none, with attempts, student' => [
733                 1, manager::REVIEWNONE, true, 'student', [null, null, null]
734             ],
735             'Tracking enabled, review own, with attempts, student' => [
736                 1, manager::REVIEWCOMPLETION, true, 'student', ['attempts', 'attempts', 'results']
737             ],
738         ];
739     }
741     /**
742      * Test get_attempt method.
743      *
744      * @dataProvider get_attempt_data
745      * @param string $attemptname the attempt to use
746      * @param string|null $result the expected attempt ID or null for none
747      */
748     public function test_get_attempt(string $attemptname, ?string $result): void {
750         $this->resetAfterTest();
751         $this->setAdminUser();
753         $course = $this->getDataGenerator()->create_course();
755         $activity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
756         $cm = get_coursemodule_from_id('h5pactivity', $activity->cmid, 0, false, MUST_EXIST);
758         $otheractivity = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
759         $othercm = get_coursemodule_from_id('h5pactivity', $otheractivity->cmid, 0, false, MUST_EXIST);
761         $manager = manager::create_from_instance($activity);
763         $user = $this->getDataGenerator()->create_and_enrol($course, 'student');
765         $attempts = ['inexistent' => 0];
767         $this->generate_fake_attempts($activity, $user, 1);
768         $attempt = attempt::last_attempt($user, $cm);
769         $attempts['current'] = $attempt->get_id();
771         $this->generate_fake_attempts($otheractivity, $user, 1);
772         $attempt = attempt::last_attempt($user, $othercm);
773         $attempts['other'] = $attempt->get_id();
775         $attempt = $manager->get_attempt($attempts[$attemptname]);
776         if ($result === null) {
777             $this->assertNull($attempt);
778         } else {
779             $this->assertEquals($attempts[$attemptname], $attempt->get_id());
780             $this->assertEquals($activity->id, $attempt->get_h5pactivityid());
781             $this->assertEquals($user->id, $attempt->get_userid());
782             $this->assertEquals(4, $attempt->get_attempt());
783         }
784     }
786     /**
787      * Data provider for test_get_attempt.
788      *
789      * @return array
790      */
791     public function get_attempt_data(): array {
792         return [
793             'Get the current activity attempt' => [
794                 'current', 'current'
795             ],
796             'Try to get another activity attempt' => [
797                 'other', null
798             ],
799             'Try to get an inexistent attempt' => [
800                 'inexistent', null
801             ],
802         ];
803     }
805     /**
806      * Insert fake attempt data into h5pactiviyt_attempts.
807      *
808      * This function insert 4 attempts. 3 of them finished with different gradings
809      * and timestamps and 1 unfinished.
810      *
811      * @param stdClass $activity the activity record
812      * @param stdClass $user user record
813      * @param int $basescore a score to be used to generate all attempts
814      */
815     private function generate_fake_attempts(stdClass $activity, stdClass $user, int $basescore) {
816         global $DB;
818         $attempt = (object)[
819             'h5pactivityid' => $activity->id,
820             'userid' => $user->id,
821             'timecreated' => $basescore,
822             'timemodified' => ($basescore + 10),
823             'attempt' => 1,
824             'rawscore' => $basescore,
825             'maxscore' => ($basescore + $basescore),
826             'duration' => $basescore,
827             'completion' => 1,
828             'success' => 1,
829         ];
830         $attempt->scaled = $attempt->rawscore / $attempt->maxscore;
831         $DB->insert_record('h5pactivity_attempts', $attempt);
833         $attempt = (object)[
834             'h5pactivityid' => $activity->id,
835             'userid' => $user->id,
836             'timecreated' => ($basescore + 20),
837             'timemodified' => ($basescore + 30),
838             'attempt' => 2,
839             'rawscore' => $basescore,
840             'maxscore' => ($basescore + $basescore - 1),
841             'duration' => $basescore,
842             'completion' => 1,
843             'success' => 1,
844         ];
845         $attempt->scaled = $attempt->rawscore / $attempt->maxscore;
846         $DB->insert_record('h5pactivity_attempts', $attempt);
848         $attempt = (object)[
849             'h5pactivityid' => $activity->id,
850             'userid' => $user->id,
851             'timecreated' => ($basescore + 40),
852             'timemodified' => ($basescore + 50),
853             'attempt' => 3,
854             'rawscore' => $basescore,
855             'maxscore' => ($basescore + $basescore + 1),
856             'duration' => $basescore,
857             'completion' => 1,
858             'success' => 0,
859         ];
860         $attempt->scaled = $attempt->rawscore / $attempt->maxscore;
861         $DB->insert_record('h5pactivity_attempts', $attempt);
863         // Unfinished attempt.
864         $attempt = (object)[
865             'h5pactivityid' => $activity->id,
866             'userid' => $user->id,
867             'timecreated' => ($basescore + 60),
868             'timemodified' => ($basescore + 60),
869             'attempt' => 4,
870             'rawscore' => $basescore,
871             'maxscore' => $basescore,
872             'duration' => $basescore,
873         ];
874         $DB->insert_record('h5pactivity_attempts', $attempt);
875     }