MDL-47691 quiz: only warn re overdue attempts if a Q has been answered
[moodle.git] / mod / quiz / tests / attempt_walkthrough_test.php
CommitLineData
2baf8e8a
JP
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 attempt walk through tests.
19 *
20 * @package mod_quiz
21 * @category phpunit
22 * @copyright 2013 The Open University
23 * @author Jamie Pratt <me@jamiep.org>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
2baf8e8a
JP
30require_once($CFG->dirroot . '/mod/quiz/locallib.php');
31
32/**
33 * Quiz attempt walk through.
34 *
35 * @package mod_quiz
36 * @category phpunit
37 * @copyright 2013 The Open University
38 * @author Jamie Pratt <me@jamiep.org>
39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 */
41class mod_quiz_attempt_walkthrough_testcase extends advanced_testcase {
42
43 /**
44 * Create a quiz with questions and walk through a quiz attempt.
45 */
46 public function test_quiz_attempt_walkthrough() {
47 global $SITE;
48
49 $this->resetAfterTest(true);
50
51 // Make a quiz.
52 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
53
54 $quiz = $quizgenerator->create_instance(array('course'=>$SITE->id, 'questionsperpage' => 0, 'grade' => 100.0,
55 'sumgrades' => 2));
56
57 // Create a couple of questions.
58 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
59
60 $cat = $questiongenerator->create_question_category();
61 $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
62 $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
63
64 // Add them to the quiz.
65 quiz_add_quiz_question($saq->id, $quiz);
66 quiz_add_quiz_question($numq->id, $quiz);
67
68 // Make a user to do the quiz.
69 $user1 = $this->getDataGenerator()->create_user();
2baf8e8a
JP
70
71 $quizobj = quiz::create($quiz->id, $user1->id);
72
73 // Start the attempt.
74 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
75 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
76
77 $timenow = time();
70782526 78 $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $user1->id);
2baf8e8a
JP
79
80 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow);
ccba5b88 81 $this->assertEquals('1,2,0', $attempt->layout);
2baf8e8a
JP
82
83 quiz_attempt_save_started($quizobj, $quba, $attempt);
84
85 // Process some responses from the student.
86 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0
TH
87 $this->assertFalse($attemptobj->has_response_to_at_least_one_graded_question());
88
2baf8e8a
JP
89 $prefix1 = $quba->get_field_prefix(1);
90 $prefix2 = $quba->get_field_prefix(2);
91
388f0473
JP
92 $tosubmit = array(1 => array('answer' => 'frog'),
93 2 => array('answer' => '3.14'));
2baf8e8a
JP
94
95 $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
96
97 // Finish the attempt.
98 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0 99 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
2baf8e8a
JP
100 $attemptobj->process_finish($timenow, false);
101
102 // Re-load quiz attempt data.
103 $attemptobj = quiz_attempt::create($attempt->id);
104
105 // Check that results are stored as expected.
106 $this->assertEquals(1, $attemptobj->get_attempt_number());
107 $this->assertEquals(2, $attemptobj->get_sum_marks());
108 $this->assertEquals(true, $attemptobj->is_finished());
109 $this->assertEquals($timenow, $attemptobj->get_submitted_date());
110 $this->assertEquals($user1->id, $attemptobj->get_userid());
1c2e05c0 111 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
2baf8e8a
JP
112
113 // Check quiz grades.
114 $grades = quiz_get_user_grades($quiz, $user1->id);
115 $grade = array_shift($grades);
116 $this->assertEquals(100.0, $grade->rawgrade);
117
118 // Check grade book.
119 $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $quiz->id, $user1->id);
120 $gradebookitem = array_shift($gradebookgrades->items);
121 $gradebookgrade = array_shift($gradebookitem->grades);
122 $this->assertEquals(100, $gradebookgrade->grade);
123 }
388f0473
JP
124
125 /**
c2f2e7f0 126 * Create a quiz with a random as well as other questions and walk through quiz attempts.
388f0473
JP
127 */
128 public function test_quiz_with_random_question_attempt_walkthrough() {
129 global $SITE;
130
131 $this->resetAfterTest(true);
132 question_bank::get_qtype('random')->clear_caches_before_testing();
133
134 $this->setAdminUser();
135
136 // Make a quiz.
137 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
138
ccba5b88 139 $quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 2, 'grade' => 100.0,
388f0473
JP
140 'sumgrades' => 4));
141
142 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
143
144 // Add two questions to question category.
145 $cat = $questiongenerator->create_question_category();
146 $saq = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
147 $numq = $questiongenerator->create_question('numerical', null, array('category' => $cat->id));
148
149 // Add random question to the quiz.
150 quiz_add_random_questions($quiz, 0, $cat->id, 1, false);
151
152 // Make another category.
153 $cat2 = $questiongenerator->create_question_category();
154 $match = $questiongenerator->create_question('match', null, array('category' => $cat->id));
155
156 quiz_add_quiz_question($match->id, $quiz, 0);
157
158 $multichoicemulti = $questiongenerator->create_question('multichoice', 'two_of_four', array('category' => $cat->id));
159
160 quiz_add_quiz_question($multichoicemulti->id, $quiz, 0);
161
162 $multichoicesingle = $questiongenerator->create_question('multichoice', 'one_of_four', array('category' => $cat->id));
163
164 quiz_add_quiz_question($multichoicesingle->id, $quiz, 0);
165
c2f2e7f0
JP
166 foreach (array($saq->id => 'frog', $numq->id => '3.14') as $randomqidtoselect => $randqanswer) {
167 // Make a new user to do the quiz each loop.
168 $user1 = $this->getDataGenerator()->create_user();
169 $this->setUser($user1);
388f0473 170
c2f2e7f0 171 $quizobj = quiz::create($quiz->id, $user1->id);
388f0473 172
c2f2e7f0
JP
173 // Start the attempt.
174 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
175 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
388f0473 176
c2f2e7f0
JP
177 $timenow = time();
178 $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
388f0473 179
c2f2e7f0 180 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow, array(1 => $randomqidtoselect));
ccba5b88 181 $this->assertEquals('1,2,0,3,4,0', $attempt->layout);
388f0473 182
c2f2e7f0 183 quiz_attempt_save_started($quizobj, $quba, $attempt);
388f0473 184
c2f2e7f0
JP
185 // Process some responses from the student.
186 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0 187 $this->assertFalse($attemptobj->has_response_to_at_least_one_graded_question());
388f0473 188
c2f2e7f0
JP
189 $tosubmit = array();
190 $selectedquestionid = $quba->get_question_attempt(1)->get_question()->id;
191 $tosubmit[1] = array('answer' => $randqanswer);
192 $tosubmit[2] = array(
49dda8fe
JP
193 'frog' => 'amphibian',
194 'cat' => 'mammal',
195 'newt' => 'amphibian');
196 $tosubmit[3] = array('One' => '1', 'Two' => '0', 'Three' => '1', 'Four' => '0'); // First and third choice.
197 $tosubmit[4] = array('answer' => 'One'); // The first choice.
388f0473 198
c2f2e7f0 199 $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
388f0473 200
c2f2e7f0
JP
201 // Finish the attempt.
202 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0 203 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
c2f2e7f0 204 $attemptobj->process_finish($timenow, false);
388f0473 205
c2f2e7f0
JP
206 // Re-load quiz attempt data.
207 $attemptobj = quiz_attempt::create($attempt->id);
388f0473 208
c2f2e7f0
JP
209 // Check that results are stored as expected.
210 $this->assertEquals(1, $attemptobj->get_attempt_number());
211 $this->assertEquals(4, $attemptobj->get_sum_marks());
212 $this->assertEquals(true, $attemptobj->is_finished());
213 $this->assertEquals($timenow, $attemptobj->get_submitted_date());
214 $this->assertEquals($user1->id, $attemptobj->get_userid());
1c2e05c0 215 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
388f0473 216
c2f2e7f0
JP
217 // Check quiz grades.
218 $grades = quiz_get_user_grades($quiz, $user1->id);
219 $grade = array_shift($grades);
220 $this->assertEquals(100.0, $grade->rawgrade);
388f0473 221
c2f2e7f0
JP
222 // Check grade book.
223 $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $quiz->id, $user1->id);
224 $gradebookitem = array_shift($gradebookgrades->items);
225 $gradebookgrade = array_shift($gradebookitem->grades);
226 $this->assertEquals(100, $gradebookgrade->grade);
227 }
388f0473 228 }
c2b051c7
JP
229
230
231 public function get_correct_response_for_variants() {
232 return array(array(1, 9.9), array(2, 8.5), array(5, 14.2), array(10, 6.8, true));
233 }
234
235 protected $quizwithvariants = null;
236
237 /**
238 * Create a quiz with a single question with variants and walk through quiz attempts.
239 *
240 * @dataProvider get_correct_response_for_variants
241 */
242 public function test_quiz_with_question_with_variants_attempt_walkthrough($variantno, $correctresponse, $done = false) {
243 global $SITE;
244
245 $this->resetAfterTest($done);
246
247 $this->setAdminUser();
248
249 if ($this->quizwithvariants === null) {
250 // Make a quiz.
251 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
252
253 $this->quizwithvariants = $quizgenerator->create_instance(array('course'=>$SITE->id,
254 'questionsperpage' => 0,
255 'grade' => 100.0,
256 'sumgrades' => 1));
257
258 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
259
260 $cat = $questiongenerator->create_question_category();
261 $calc = $questiongenerator->create_question('calculatedsimple', 'sumwithvariants', array('category' => $cat->id));
262 quiz_add_quiz_question($calc->id, $this->quizwithvariants, 0);
263 }
264
265
266 // Make a new user to do the quiz.
267 $user1 = $this->getDataGenerator()->create_user();
268 $this->setUser($user1);
269 $quizobj = quiz::create($this->quizwithvariants->id, $user1->id);
270
271 // Start the attempt.
272 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context());
273 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour);
274
275 $timenow = time();
276 $attempt = quiz_create_attempt($quizobj, 1, false, $timenow);
ccba5b88 277
c2b051c7
JP
278 // Select variant.
279 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow, array(), array(1 => $variantno));
ccba5b88 280 $this->assertEquals('1,0', $attempt->layout);
c2b051c7
JP
281 quiz_attempt_save_started($quizobj, $quba, $attempt);
282
283 // Process some responses from the student.
284 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0
TH
285 $this->assertFalse($attemptobj->has_response_to_at_least_one_graded_question());
286
c2b051c7
JP
287 $tosubmit = array(1 => array('answer' => $correctresponse));
288 $attemptobj->process_submitted_actions($timenow, false, $tosubmit);
289
290 // Finish the attempt.
291 $attemptobj = quiz_attempt::create($attempt->id);
1c2e05c0
TH
292 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
293
c2b051c7
JP
294 $attemptobj->process_finish($timenow, false);
295
296 // Re-load quiz attempt data.
297 $attemptobj = quiz_attempt::create($attempt->id);
298
299 // Check that results are stored as expected.
300 $this->assertEquals(1, $attemptobj->get_attempt_number());
301 $this->assertEquals(1, $attemptobj->get_sum_marks());
302 $this->assertEquals(true, $attemptobj->is_finished());
303 $this->assertEquals($timenow, $attemptobj->get_submitted_date());
304 $this->assertEquals($user1->id, $attemptobj->get_userid());
1c2e05c0 305 $this->assertTrue($attemptobj->has_response_to_at_least_one_graded_question());
c2b051c7
JP
306
307 // Check quiz grades.
308 $grades = quiz_get_user_grades($this->quizwithvariants, $user1->id);
309 $grade = array_shift($grades);
310 $this->assertEquals(100.0, $grade->rawgrade);
311
312 // Check grade book.
313 $gradebookgrades = grade_get_grades($SITE->id, 'mod', 'quiz', $this->quizwithvariants->id, $user1->id);
314 $gradebookitem = array_shift($gradebookgrades->items);
315 $gradebookgrade = array_shift($gradebookitem->grades);
316 $this->assertEquals(100, $gradebookgrade->grade);
317 }
2baf8e8a 318}