MDL-32323 convert question tests
[moodle.git] / question / engine / tests / questionattempt_test.php
CommitLineData
603bd001
PS
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 the {@link question_attempt} class.
39 *
40 * These are the tests that don't require any steps.
41 *
42 * @copyright 2009 The Open University
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 */
45class question_attempt_test extends advanced_testcase {
46 private $question;
47 private $usageid;
48 private $qa;
49
50 protected function setUp() {
51 $this->question = test_question_maker::make_question('description');
52 $this->question->defaultmark = 3;
53 $this->usageid = 13;
54 $this->qa = new question_attempt($this->question, $this->usageid);
55 }
56
57 protected function tearDown() {
58 $this->question = null;
59 $this->useageid = null;
60 $this->qa = null;
61 }
62
63 public function test_constructor_sets_maxmark() {
64 $qa = new question_attempt($this->question, $this->usageid);
65 $this->assertSame($this->question, $qa->get_question());
66 $this->assertEquals(3, $qa->get_max_mark());
67 }
68
69 public function test_maxmark_beats_default_mark() {
70 $qa = new question_attempt($this->question, $this->usageid, null, 2);
71 $this->assertEquals(2, $qa->get_max_mark());
72 }
73
74 public function test_get_set_slot() {
75 $this->qa->set_slot(7);
76 $this->assertEquals(7, $this->qa->get_slot());
77 }
78
79 public function test_fagged_initially_false() {
80 $this->assertEquals(false, $this->qa->is_flagged());
81 }
82
83 public function test_set_is_flagged() {
84 $this->qa->set_flagged(true);
85 $this->assertEquals(true, $this->qa->is_flagged());
86 }
87
88 public function test_get_qt_field_name() {
89 $name = $this->qa->get_qt_field_name('test');
90 $this->assertRegExp('/^' . preg_quote($this->qa->get_field_prefix()) . '/', $name);
91 $this->assertRegExp('/_test$/', $name);
92 }
93
94 public function test_get_behaviour_field_name() {
95 $name = $this->qa->get_behaviour_field_name('test');
96 $this->assertRegExp('/^' . preg_quote($this->qa->get_field_prefix()) . '/', $name);
97 $this->assertRegExp('/_-test$/', $name);
98 }
99
100 public function test_get_field_prefix() {
101 $this->qa->set_slot(7);
102 $name = $this->qa->get_field_prefix();
103 $this->assertRegExp('/' . preg_quote($this->usageid) . '/', $name);
104 $this->assertRegExp('/' . preg_quote($this->qa->get_slot()) . '/', $name);
105 }
106
107 public function test_get_submitted_var_not_present_var_returns_null() {
108 $this->assertNull($this->qa->get_submitted_var(
109 'reallyunlikelyvariablename', PARAM_BOOL));
110 }
111
112 public function test_get_submitted_var_param_mark_not_present() {
113 $this->assertNull($this->qa->get_submitted_var(
114 'name', question_attempt::PARAM_MARK, array()));
115 }
116
117 public function test_get_submitted_var_param_mark_blank() {
118 $this->assertSame('', $this->qa->get_submitted_var(
119 'name', question_attempt::PARAM_MARK, array('name' => '')));
120 }
121
122 public function test_get_submitted_var_param_mark_number() {
123 $this->assertSame(123.0, $this->qa->get_submitted_var(
124 'name', question_attempt::PARAM_MARK, array('name' => '123')));
125 }
126
127 public function test_get_submitted_var_param_mark_number_uk_decimal() {
128 $this->assertSame(123.45, $this->qa->get_submitted_var(
129 'name', question_attempt::PARAM_MARK, array('name' => '123.45')));
130 }
131
132 public function test_get_submitted_var_param_mark_number_eu_decimal() {
133 $this->assertSame(123.45, $this->qa->get_submitted_var(
134 'name', question_attempt::PARAM_MARK, array('name' => '123,45')));
135 }
136
137 public function test_get_submitted_var_param_mark_invalid() {
138 $this->assertSame(0.0, $this->qa->get_submitted_var(
139 'name', question_attempt::PARAM_MARK, array('name' => 'frog')));
140 }
141}
142
143
144/**
145 * These tests use a standard fixture of a {@link question_attempt} with three steps.
146 *
147 * @copyright 2009 The Open University
148 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
149 */
150class question_attempt_with_steps_test extends advanced_testcase {
151 private $question;
152 private $qa;
153
154 protected function setUp() {
155 $this->question = test_question_maker::make_question('description');
156 $this->qa = new testable_question_attempt($this->question, 0, null, 2);
157 for ($i = 0; $i < 3; $i++) {
158 $step = new question_attempt_step(array('i' => $i));
159 $this->qa->add_step($step);
160 }
161 }
162
163 protected function tearDown() {
164 $this->qa = null;
165 }
166
167 public function test_get_step_before_start() {
168 $this->setExpectedException('moodle_exception');
169 $step = $this->qa->get_step(-1);
170 }
171
172 public function test_get_step_at_start() {
173 $step = $this->qa->get_step(0);
174 $this->assertEquals(0, $step->get_qt_var('i'));
175 }
176
177 public function test_get_step_at_end() {
178 $step = $this->qa->get_step(2);
179 $this->assertEquals(2, $step->get_qt_var('i'));
180 }
181
182 public function test_get_step_past_end() {
183 $this->setExpectedException('moodle_exception');
184 $step = $this->qa->get_step(3);
185 }
186
187 public function test_get_num_steps() {
188 $this->assertEquals(3, $this->qa->get_num_steps());
189 }
190
191 public function test_get_last_step() {
192 $step = $this->qa->get_last_step();
193 $this->assertEquals(2, $step->get_qt_var('i'));
194 }
195
196 public function test_get_last_qt_var_there1() {
197 $this->assertEquals(2, $this->qa->get_last_qt_var('i'));
198 }
199
200 public function test_get_last_qt_var_there2() {
201 $this->qa->get_step(0)->set_qt_var('_x', 'a value');
202 $this->assertEquals('a value', $this->qa->get_last_qt_var('_x'));
203 }
204
205 public function test_get_last_qt_var_missing() {
206 $this->assertNull($this->qa->get_last_qt_var('notthere'));
207 }
208
209 public function test_get_last_qt_var_missing_default() {
210 $this->assertEquals('default', $this->qa->get_last_qt_var('notthere', 'default'));
211 }
212
213 public function test_get_last_behaviour_var_missing() {
214 $this->assertNull($this->qa->get_last_qt_var('notthere'));
215 }
216
217 public function test_get_last_behaviour_var_there() {
218 $this->qa->get_step(1)->set_behaviour_var('_x', 'a value');
219 $this->assertEquals('a value', '' . $this->qa->get_last_behaviour_var('_x'));
220 }
221
222 public function test_get_state_gets_state_of_last() {
223 $this->qa->get_step(2)->set_state(question_state::$gradedright);
224 $this->qa->get_step(1)->set_state(question_state::$gradedwrong);
225 $this->assertEquals(question_state::$gradedright, $this->qa->get_state());
226 }
227
228 public function test_get_mark_gets_mark_of_last() {
229 $this->assertEquals(2, $this->qa->get_max_mark());
230 $this->qa->get_step(2)->set_fraction(0.5);
231 $this->qa->get_step(1)->set_fraction(0.1);
232 $this->assertEquals(1, $this->qa->get_mark());
233 }
234
235 public function test_get_fraction_gets_fraction_of_last() {
236 $this->qa->get_step(2)->set_fraction(0.5);
237 $this->qa->get_step(1)->set_fraction(0.1);
238 $this->assertEquals(0.5, $this->qa->get_fraction());
239 }
240
241 public function test_get_fraction_returns_null_if_none() {
242 $this->assertNull($this->qa->get_fraction());
243 }
244
245 public function test_format_mark() {
246 $this->qa->get_step(2)->set_fraction(0.5);
247 $this->assertEquals('1.00', $this->qa->format_mark(2));
248 }
249
250 public function test_format_max_mark() {
251 $this->assertEquals('2.0000000', $this->qa->format_max_mark(7));
252 }
253
254 public function test_get_min_fraction() {
255 $this->qa->set_min_fraction(-1);
256 $this->assertEquals(-1, $this->qa->get_min_fraction(0));
257 }
258
259 public function test_cannot_get_min_fraction_before_start() {
260 $qa = new question_attempt($this->question, 0);
261 $this->setExpectedException('moodle_exception');
262 $qa->get_min_fraction();
263 }
264}
265
266
267/**
268 * Unit tests for loading data into the {@link question_attempt} class.
269 *
270 * @copyright 2009 The Open University
271 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
272 */
273class question_attempt_db_test extends data_loading_method_test_base {
274 public function test_load() {
275 $records = new question_test_recordset(array(
276 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
277 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
278 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
279 'attemptstepid', 'sequencenumber', 'state', 'fraction',
280 'timecreated', 'userid', 'name', 'value'),
281 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
282 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 2, 1, 'complete', null, 1256233705, 1, 'answer', '1'),
283 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 1, '', '', '', 1256233790, 3, 2, 'complete', null, 1256233710, 1, 'answer', '0'),
284 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 4, 3, 'complete', null, 1256233715, 1, 'answer', '1'),
285 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 5, 4, 'gradedright', 1.0000000, 1256233720, 1, '-finish', '1'),
286 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!'),
287 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-mark', '1'),
288 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 6, 5, 'mangrpartial', 0.5000000, 1256233790, 1, '-maxmark', '2'),
289 ));
290
291 $question = test_question_maker::make_question('truefalse', 'true');
292 $question->id = -1;
293
294 question_bank::start_unit_test();
295 question_bank::load_test_question_data($question);
296 $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
297 question_bank::end_unit_test();
298
299 $this->assertEquals($question->questiontext, $qa->get_question()->questiontext);
300
301 $this->assertEquals(6, $qa->get_num_steps());
302
303 $step = $qa->get_step(0);
304 $this->assertEquals(question_state::$todo, $step->get_state());
305 $this->assertNull($step->get_fraction());
306 $this->assertEquals(1256233700, $step->get_timecreated());
307 $this->assertEquals(1, $step->get_user_id());
308 $this->assertEquals(array(), $step->get_all_data());
309
310 $step = $qa->get_step(1);
311 $this->assertEquals(question_state::$complete, $step->get_state());
312 $this->assertNull($step->get_fraction());
313 $this->assertEquals(1256233705, $step->get_timecreated());
314 $this->assertEquals(1, $step->get_user_id());
315 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
316
317 $step = $qa->get_step(2);
318 $this->assertEquals(question_state::$complete, $step->get_state());
319 $this->assertNull($step->get_fraction());
320 $this->assertEquals(1256233710, $step->get_timecreated());
321 $this->assertEquals(1, $step->get_user_id());
322 $this->assertEquals(array('answer' => '0'), $step->get_all_data());
323
324 $step = $qa->get_step(3);
325 $this->assertEquals(question_state::$complete, $step->get_state());
326 $this->assertNull($step->get_fraction());
327 $this->assertEquals(1256233715, $step->get_timecreated());
328 $this->assertEquals(1, $step->get_user_id());
329 $this->assertEquals(array('answer' => '1'), $step->get_all_data());
330
331 $step = $qa->get_step(4);
332 $this->assertEquals(question_state::$gradedright, $step->get_state());
333 $this->assertEquals(1, $step->get_fraction());
334 $this->assertEquals(1256233720, $step->get_timecreated());
335 $this->assertEquals(1, $step->get_user_id());
336 $this->assertEquals(array('-finish' => '1'), $step->get_all_data());
337
338 $step = $qa->get_step(5);
339 $this->assertEquals(question_state::$mangrpartial, $step->get_state());
340 $this->assertEquals(0.5, $step->get_fraction());
341 $this->assertEquals(1256233790, $step->get_timecreated());
342 $this->assertEquals(1, $step->get_user_id());
343 $this->assertEquals(array('-comment' => 'Not good enough!', '-mark' => '1', '-maxmark' => '2'),
344 $step->get_all_data());
345 }
346
347 public function test_load_missing_question() {
348 $records = new question_test_recordset(array(
349 array('questionattemptid', 'contextid', 'questionusageid', 'slot',
350 'behaviour', 'questionid', 'variant', 'maxmark', 'minfraction', 'flagged',
351 'questionsummary', 'rightanswer', 'responsesummary', 'timemodified',
352 'attemptstepid', 'sequencenumber', 'state', 'fraction',
353 'timecreated', 'userid', 'name', 'value'),
354 array(1, 123, 1, 1, 'deferredfeedback', -1, 1, 2.0000000, 0.0000000, 0, '', '', '', 1256233790, 1, 0, 'todo', null, 1256233700, 1, null, null),
355 ));
356
357 question_bank::start_unit_test();
358 $qa = question_attempt::load_from_records($records, 1, new question_usage_null_observer(), 'deferredfeedback');
359 question_bank::end_unit_test();
360
361 $missingq = question_bank::get_qtype('missingtype')->make_deleted_instance(-1, 2);
362 $this->assertEquals($missingq, $qa->get_question());
363
364 $this->assertEquals(1, $qa->get_num_steps());
365
366 $step = $qa->get_step(0);
367 $this->assertEquals(question_state::$todo, $step->get_state());
368 $this->assertNull($step->get_fraction());
369 $this->assertEquals(1256233700, $step->get_timecreated());
370 $this->assertEquals(1, $step->get_user_id());
371 $this->assertEquals(array(), $step->get_all_data());
372 }
373}