MDL-32188 quiz/question: behaviours can add to the review summary.
[moodle.git] / question / engine / tests / questionattempt_db_test.php
CommitLineData
eca230b5
TH
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 * This file contains tests for the question_attempt class.
19 *
20 * Action methods like start, process_action and finish are assumed to be
21 * tested by walkthrough tests in the various behaviours.
22 *
23 * @package moodlecore
24 * @subpackage questionengine
25 * @copyright 2009 The Open University
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 */
28
29
30defined('MOODLE_INTERNAL') || die();
31
32global $CFG;
33require_once(dirname(__FILE__) . '/../lib.php');
34require_once(dirname(__FILE__) . '/helpers.php');
35
36
37/**
38 * Unit tests for loading data into the {@link question_attempt} class.
39 *
40 * @copyright 2009 The Open University
41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 */
43class question_attempt_db_test extends data_loading_method_test_base {
44 public function test_load() {
45 $records = new question_test_recordset(array(
46 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
47 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
48 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
49 'attemptstepid', 'sequencenumber', 'state', 'fraction',
50 'timecreated', 'userid', 'name', 'value'),
51 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
52 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'),
53 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'),
54 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, 3, 'complete', null, 1256233715, 1, 'answer', '1'),
55 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 4, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'),
56 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-comment', 'Not good enough!'),
57 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-mark', '1'),
58 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-maxmark', '2'),
59 ));
60
61 $question = test_question_maker::make_question('truefalse', 'true');
62 $question->id = -1;
63
64 question_bank::start_unit_test();
65 question_bank::load_test_question_data($question);
66 $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
67 question_bank::end_unit_test();
68
69 $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
70
71 $this->assertEquals(6, $qa->get_num_steps());
72
73 $step = $qa->get_step(0);
74 $this->assertEquals(question_state::$todo, $step->get_state());
75 $this->assertNull($step->get_fraction());
76 $this->assertEquals(1256233700, $step->get_timecreated());
77 $this->assertEquals(1, $step->get_user_id());
78 $this->assertEquals(array(), $step->get_all_data());
79
80 $step = $qa->get_step(1);
81 $this->assertEquals(question_state::$complete, $step->get_state());
82 $this->assertNull($step->get_fraction());
83 $this->assertEquals(1256233705, $step->get_timecreated());
84 $this->assertEquals(1, $step->get_user_id());
85 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
86
87 $step = $qa->get_step(2);
88 $this->assertEquals(question_state::$complete, $step->get_state());
89 $this->assertNull($step->get_fraction());
90 $this->assertEquals(1256233710, $step->get_timecreated());
91 $this->assertEquals(1, $step->get_user_id());
92 $this->assertEquals(array('answer' => '0'), $step->get_all_data());
93
94 $step = $qa->get_step(3);
95 $this->assertEquals(question_state::$complete, $step->get_state());
96 $this->assertNull($step->get_fraction());
97 $this->assertEquals(1256233715, $step->get_timecreated());
98 $this->assertEquals(1, $step->get_user_id());
99 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
100
101 $step = $qa->get_step(4);
102 $this->assertEquals(question_state::$gradedright, $step->get_state());
103 $this->assertEquals(1, $step->get_fraction());
104 $this->assertEquals(1256233720, $step->get_timecreated());
105 $this->assertEquals(1, $step->get_user_id());
106 $this->assertEquals(array('-finish' => '1'), $step->get_all_data());
107
108 $step = $qa->get_step(5);
109 $this->assertEquals(question_state::$mangrpartial, $step->get_state());
110 $this->assertEquals(0.5, $step->get_fraction());
111 $this->assertEquals(1256233790, $step->get_timecreated());
112 $this->assertEquals(1, $step->get_user_id());
113 $this->assertEquals(array('-comment' => 'Not good enough!', '-mark' => '1', '-maxmark' => '2'),
114 $step->get_all_data());
115 }
116
117 public function test_load_missing_question() {
118 $records = new question_test_recordset(array(
119 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
120 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
121 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
122 'attemptstepid', 'sequencenumber', 'state', 'fraction',
123 'timecreated', 'userid', 'name', 'value'),
124 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
125 ));
126
127 question_bank::start_unit_test();
128 $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
129 question_bank::end_unit_test();
130
131 $missingq = question_bank::get_qtype('missingtype')->make_deleted_instance(-1, 2);
132 $this->assertEquals($missingq, $qa->get_question());
133
134 $this->assertEquals(1, $qa->get_num_steps());
135
136 $step = $qa->get_step(0);
137 $this->assertEquals(question_state::$todo, $step->get_state());
138 $this->assertNull($step->get_fraction());
139 $this->assertEquals(1256233700, $step->get_timecreated());
140 $this->assertEquals(1, $step->get_user_id());
141 $this->assertEquals(array(), $step->get_all_data());
142 }
0a606a2b
TH
143
144 public function test_load_with_autosaved_data() {
145 $records = new question_test_recordset(array(
146 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
147 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
148 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
149 'attemptstepid', 'sequencenumber', 'state', 'fraction',
150 'timecreated', 'userid', 'name', 'value'),
151 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, -3, 'complete', null, 1256233715, 1, 'answer', '1'),
152 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
153 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'),
154 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'),
155 ));
156
157 $question = test_question_maker::make_question('truefalse', 'true');
158 $question->id = -1;
159
160 question_bank::start_unit_test();
161 question_bank::load_test_question_data($question);
162 $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
163 question_bank::end_unit_test();
164
165 $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
166
167 $this->assertEquals(4, $qa->get_num_steps());
168 $this->assertTrue($qa->has_autosaved_step());
169
170 $step = $qa->get_step(0);
171 $this->assertEquals(question_state::$todo, $step->get_state());
172 $this->assertNull($step->get_fraction());
173 $this->assertEquals(1256233700, $step->get_timecreated());
174 $this->assertEquals(1, $step->get_user_id());
175 $this->assertEquals(array(), $step->get_all_data());
176
177 $step = $qa->get_step(1);
178 $this->assertEquals(question_state::$complete, $step->get_state());
179 $this->assertNull($step->get_fraction());
180 $this->assertEquals(1256233705, $step->get_timecreated());
181 $this->assertEquals(1, $step->get_user_id());
182 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
183
184 $step = $qa->get_step(2);
185 $this->assertEquals(question_state::$complete, $step->get_state());
186 $this->assertNull($step->get_fraction());
187 $this->assertEquals(1256233710, $step->get_timecreated());
188 $this->assertEquals(1, $step->get_user_id());
189 $this->assertEquals(array('answer' => '0'), $step->get_all_data());
190
191 $step = $qa->get_step(3);
192 $this->assertEquals(question_state::$complete, $step->get_state());
193 $this->assertNull($step->get_fraction());
194 $this->assertEquals(1256233715, $step->get_timecreated());
195 $this->assertEquals(1, $step->get_user_id());
196 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
197 }
198
199 public function test_load_with_unnecessary_autosaved_data() {
200 // The point here is that the somehow (probably due to two things
201 // happening concurrently, we have autosaved data in the database that
202 // has already been superceded by real data, so it should be ignored.
203 // There is also a second lot of redundant data to delete.
204 $records = new question_test_recordset(array(
205 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
206 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
207 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
208 'attemptstepid', 'sequencenumber', 'state', 'fraction',
209 'timecreated', 'userid', 'name', 'value'),
210 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, -2, 'complete', null, 1256233715, 1, 'answer', '0'),
211 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, -1, 'complete', null, 1256233715, 1, 'answer', '0'),
212 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
213 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'),
214 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'),
215 ));
216
217 $question = test_question_maker::make_question('truefalse', 'true');
218 $question->id = -1;
219
220 question_bank::start_unit_test();
221 question_bank::load_test_question_data($question);
222 $observer = new testable_question_engine_unit_of_work(
223 question_engine::make_questions_usage_by_activity('unit_test', context_system::instance()));
224 $qa = question_attempt::load_from_records($records, 1, $observer, 'deferredfeedback');
225 question_bank::end_unit_test();
226
227 $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
228
229 $this->assertEquals(3, $qa->get_num_steps());
230 $this->assertFalse($qa->has_autosaved_step());
231
232 $step = $qa->get_step(0);
233 $this->assertEquals(question_state::$todo, $step->get_state());
234 $this->assertNull($step->get_fraction());
235 $this->assertEquals(1256233700, $step->get_timecreated());
236 $this->assertEquals(1, $step->get_user_id());
237 $this->assertEquals(array(), $step->get_all_data());
238
239 $step = $qa->get_step(1);
240 $this->assertEquals(question_state::$complete, $step->get_state());
241 $this->assertNull($step->get_fraction());
242 $this->assertEquals(1256233705, $step->get_timecreated());
243 $this->assertEquals(1, $step->get_user_id());
244 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
245
246 $step = $qa->get_step(2);
247 $this->assertEquals(question_state::$complete, $step->get_state());
248 $this->assertNull($step->get_fraction());
249 $this->assertEquals(1256233710, $step->get_timecreated());
250 $this->assertEquals(1, $step->get_user_id());
251 $this->assertEquals(array('answer' => '0'), $step->get_all_data());
252
253 $this->assertEquals(2, count($observer->get_steps_deleted()));
254 }
eca230b5 255}