MDL-60062 quiz: add support for drag drop of calendar events
[moodle.git] / mod / quiz / tests / locallib_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  * Unit tests for (some of) mod/quiz/locallib.php.
19  *
20  * @package    mod_quiz
21  * @category   test
22  * @copyright  2008 Tim Hunt
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->dirroot . '/mod/quiz/locallib.php');
33 /**
34  * Unit tests for (some of) mod/quiz/locallib.php.
35  *
36  * @copyright  2008 Tim Hunt
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class mod_quiz_locallib_testcase extends advanced_testcase {
41     public function test_quiz_rescale_grade() {
42         $quiz = new stdClass();
43         $quiz->decimalpoints = 2;
44         $quiz->questiondecimalpoints = 3;
45         $quiz->grade = 10;
46         $quiz->sumgrades = 10;
47         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.12345678);
48         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.12, 2));
49         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'),
50             format_float(0.123, 3));
51         $quiz->sumgrades = 5;
52         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, false), 0.24691356);
53         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.25, 2));
54         $this->assertEquals(quiz_rescale_grade(0.12345678, $quiz, 'question'),
55             format_float(0.247, 3));
56     }
58     public function quiz_attempt_state_data_provider() {
59         return [
60             [quiz_attempt::IN_PROGRESS, null, null, mod_quiz_display_options::DURING],
61             [quiz_attempt::FINISHED, -90, null, mod_quiz_display_options::IMMEDIATELY_AFTER],
62             [quiz_attempt::FINISHED, -7200, null, mod_quiz_display_options::LATER_WHILE_OPEN],
63             [quiz_attempt::FINISHED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN],
64             [quiz_attempt::FINISHED, -30, 30, mod_quiz_display_options::IMMEDIATELY_AFTER],
65             [quiz_attempt::FINISHED, -90, -30, mod_quiz_display_options::AFTER_CLOSE],
66             [quiz_attempt::FINISHED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE],
67             [quiz_attempt::FINISHED, -90, -3600, mod_quiz_display_options::AFTER_CLOSE],
68             [quiz_attempt::ABANDONED, -10000000, null, mod_quiz_display_options::LATER_WHILE_OPEN],
69             [quiz_attempt::ABANDONED, -7200, 3600, mod_quiz_display_options::LATER_WHILE_OPEN],
70             [quiz_attempt::ABANDONED, -7200, -3600, mod_quiz_display_options::AFTER_CLOSE],
71         ];
72     }
74     /**
75      * @dataProvider quiz_attempt_state_data_provider
76      *
77      * @param unknown $attemptstate as in the quiz_attempts.state DB column.
78      * @param unknown $relativetimefinish time relative to now when the attempt finished, or null for 0.
79      * @param unknown $relativetimeclose time relative to now when the quiz closes, or null for 0.
80      * @param unknown $expectedstate expected result. One of the mod_quiz_display_options constants/
81      */
82     public function test_quiz_attempt_state($attemptstate,
83             $relativetimefinish, $relativetimeclose, $expectedstate) {
85         $attempt = new stdClass();
86         $attempt->state = $attemptstate;
87         if ($relativetimefinish === null) {
88             $attempt->timefinish = 0;
89         } else {
90             $attempt->timefinish = time() + $relativetimefinish;
91         }
93         $quiz = new stdClass();
94         if ($relativetimeclose === null) {
95             $quiz->timeclose = 0;
96         } else {
97             $quiz->timeclose = time() + $relativetimeclose;
98         }
100         $this->assertEquals($expectedstate, quiz_attempt_state($quiz, $attempt));
101     }
103     public function test_quiz_question_tostring() {
104         $question = new stdClass();
105         $question->qtype = 'multichoice';
106         $question->name = 'The question name';
107         $question->questiontext = '<p>What sort of <b>inequality</b> is x &lt; y<img alt="?" src="..."></p>';
108         $question->questiontextformat = FORMAT_HTML;
110         $summary = quiz_question_tostring($question);
111         $this->assertEquals('<span class="questionname">The question name</span> ' .
112                 '<span class="questiontext">What sort of INEQUALITY is x &lt; y[?]' . "\n" . '</span>', $summary);
113     }
115     /**
116      * Test quiz_view
117      * @return void
118      */
119     public function test_quiz_view() {
120         global $CFG;
122         $CFG->enablecompletion = 1;
123         $this->resetAfterTest();
125         $this->setAdminUser();
126         // Setup test data.
127         $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
128         $quiz = $this->getDataGenerator()->create_module('quiz', array('course' => $course->id),
129                                                             array('completion' => 2, 'completionview' => 1));
130         $context = context_module::instance($quiz->cmid);
131         $cm = get_coursemodule_from_instance('quiz', $quiz->id);
133         // Trigger and capture the event.
134         $sink = $this->redirectEvents();
136         quiz_view($quiz, $course, $cm, $context);
138         $events = $sink->get_events();
139         // 2 additional events thanks to completion.
140         $this->assertCount(3, $events);
141         $event = array_shift($events);
143         // Checking that the event contains the expected values.
144         $this->assertInstanceOf('\mod_quiz\event\course_module_viewed', $event);
145         $this->assertEquals($context, $event->get_context());
146         $moodleurl = new \moodle_url('/mod/quiz/view.php', array('id' => $cm->id));
147         $this->assertEquals($moodleurl, $event->get_url());
148         $this->assertEventContextNotUsed($event);
149         $this->assertNotEmpty($event->get_name());
150         // Check completion status.
151         $completion = new completion_info($course);
152         $completiondata = $completion->get_data($cm);
153         $this->assertEquals(1, $completiondata->completionstate);
154     }
156     /**
157      * Return false when there are not overrides for this quiz instance.
158      */
159     public function test_quiz_is_overriden_calendar_event_no_override() {
160         global $CFG, $DB;
162         $this->resetAfterTest();
163         $this->setAdminUser();
165         $generator = $this->getDataGenerator();
166         $user = $generator->create_user();
167         $course = $generator->create_course();
168         $quizgenerator = $generator->get_plugin_generator('mod_quiz');
169         $quiz = $quizgenerator->create_instance(['course' => $course->id]);
171         $event = new \calendar_event((object)[
172             'modulename' => 'quiz',
173             'instance' => $quiz->id,
174             'userid' => $user->id
175         ]);
177         $this->assertFalse(quiz_is_overriden_calendar_event($event));
178     }
180     /**
181      * Return false if the given event isn't an quiz module event.
182      */
183     public function test_quiz_is_overriden_calendar_event_no_module_event() {
184         global $CFG, $DB;
186         $this->resetAfterTest();
187         $this->setAdminUser();
189         $generator = $this->getDataGenerator();
190         $user = $generator->create_user();
191         $course = $generator->create_course();
192         $quizgenerator = $generator->get_plugin_generator('mod_quiz');
193         $quiz = $quizgenerator->create_instance(['course' => $course->id]);
195         $event = new \calendar_event((object)[
196             'userid' => $user->id
197         ]);
199         $this->assertFalse(quiz_is_overriden_calendar_event($event));
200     }
202     /**
203      * Return false if there is overrides for this use but they belong to another quiz
204      * instance.
205      */
206     public function test_quiz_is_overriden_calendar_event_different_quiz_instance() {
207         global $CFG, $DB;
209         $this->resetAfterTest();
210         $this->setAdminUser();
212         $generator = $this->getDataGenerator();
213         $user = $generator->create_user();
214         $course = $generator->create_course();
215         $quizgenerator = $generator->get_plugin_generator('mod_quiz');
216         $quiz = $quizgenerator->create_instance(['course' => $course->id]);
217         $quiz2 = $quizgenerator->create_instance(['course' => $course->id]);
219         $event = new \calendar_event((object) [
220             'modulename' => 'quiz',
221             'instance' => $quiz->id,
222             'userid' => $user->id
223         ]);
225         $record = (object) [
226             'quiz' => $quiz2->id,
227             'userid' => $user->id
228         ];
230         $DB->insert_record('quiz_overrides', $record);
232         $this->assertFalse(quiz_is_overriden_calendar_event($event));
233     }
235     /**
236      * Return true if there is a user override for this event and quiz instance.
237      */
238     public function test_quiz_is_overriden_calendar_event_user_override() {
239         global $CFG, $DB;
241         $this->resetAfterTest();
242         $this->setAdminUser();
244         $generator = $this->getDataGenerator();
245         $user = $generator->create_user();
246         $course = $generator->create_course();
247         $quizgenerator = $generator->get_plugin_generator('mod_quiz');
248         $quiz = $quizgenerator->create_instance(['course' => $course->id]);
250         $event = new \calendar_event((object) [
251             'modulename' => 'quiz',
252             'instance' => $quiz->id,
253             'userid' => $user->id
254         ]);
256         $record = (object) [
257             'quiz' => $quiz->id,
258             'userid' => $user->id
259         ];
261         $DB->insert_record('quiz_overrides', $record);
263         $this->assertTrue(quiz_is_overriden_calendar_event($event));
264     }
266     /**
267      * Return true if there is a group override for the event and quiz instance.
268      */
269     public function test_quiz_is_overriden_calendar_event_group_override() {
270         global $CFG, $DB;
272         $this->resetAfterTest();
273         $this->setAdminUser();
275         $generator = $this->getDataGenerator();
276         $user = $generator->create_user();
277         $course = $generator->create_course();
278         $quizgenerator = $generator->get_plugin_generator('mod_quiz');
279         $quiz = $quizgenerator->create_instance(['course' => $course->id]);
280         $group = $this->getDataGenerator()->create_group(array('courseid' => $quiz->course));
281         $groupid = $group->id;
282         $userid = $user->id;
284         $event = new \calendar_event((object) [
285             'modulename' => 'quiz',
286             'instance' => $quiz->id,
287             'groupid' => $groupid
288         ]);
290         $record = (object) [
291             'quiz' => $quiz->id,
292             'groupid' => $groupid
293         ];
295         $DB->insert_record('quiz_overrides', $record);
297         $this->assertTrue(quiz_is_overriden_calendar_event($event));
298     }