MDL-39980 question engine: Attempt on last loses response files
[moodle.git] / question / type / essay / tests / walkthrough_test.php
CommitLineData
c0d12fc1
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 that walks essay questions through some attempts.
19 *
20 * @package qtype_essay
21 * @copyright 2013 The Open University
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25
26defined('MOODLE_INTERNAL') || die();
27
28global $CFG;
29require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
30
31
32/**
33 * Unit tests for the essay question type.
34 *
35 * @copyright 2013 The Open University
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 */
afb1b3d0 38class qtype_essay_walkthrough_testcase extends qbehaviour_walkthrough_test_base {
c0d12fc1
TH
39
40 protected function check_contains_textarea($name, $content = '', $height = 10) {
41 $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
42
43 $this->assertTag(array('tag' => 'textarea',
44 'attributes' => array('cols' => '60', 'rows' => $height,
45 'name' => $fieldname)),
46 $this->currentoutput);
47
48 if ($content) {
49 $this->assertRegExp('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
50 }
51 }
52
afb1b3d0
TH
53 /**
54 * Helper method: Store a test file with a given name and contents in a
55 * draft file area.
56 *
57 * @param int $usercontextid user context id.
58 * @param int $draftitemid draft item id.
59 * @param string $filename filename.
60 * @param string $contents file contents.
61 */
62 protected function save_file_to_draft_area($usercontextid, $draftitemid, $filename, $contents) {
63 $fs = get_file_storage();
64
65 $filerecord = new stdClass();
66 $filerecord->contextid = $usercontextid;
67 $filerecord->component = 'user';
68 $filerecord->filearea = 'draft';
69 $filerecord->itemid = $draftitemid;
70 $filerecord->filepath = '/';
71 $filerecord->filename = $filename;
72 $fs->create_file_from_string($filerecord, $contents);
73 }
74
c0d12fc1
TH
75 public function test_deferred_feedback_html_editor() {
76
60527d0c 77 // Create an essay question.
c0d12fc1
TH
78 $q = test_question_maker::make_question('essay', 'editor');
79 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
80
81 $prefix = $this->quba->get_field_prefix($this->slot);
82 $fieldname = $prefix . 'answer';
83 $response = '<p>The <b>cat</b> sat on the mat. Then it ate a <b>frog</b>.</p>';
84
85 // Check the initial state.
86 $this->check_current_state(question_state::$todo);
87 $this->check_current_mark(null);
88 $this->render();
89 $this->check_contains_textarea('answer', '');
90 $this->check_current_output(
91 $this->get_contains_question_text_expectation($q),
92 $this->get_does_not_contain_feedback_expectation());
93 $this->check_step_count(1);
94
95 // Save a response.
96 $this->quba->process_all_actions(null, array(
97 'slots' => $this->slot,
98 $fieldname => $response,
99 $fieldname . 'format' => FORMAT_HTML,
100 $prefix . ':sequencecheck' => '1',
101 ));
102
103 // Verify.
104 $this->check_current_state(question_state::$complete);
105 $this->check_current_mark(null);
106 $this->check_step_count(2);
107 $this->render();
108 $this->check_contains_textarea('answer', $response);
109 $this->check_current_output(
110 $this->get_contains_question_text_expectation($q),
111 $this->get_does_not_contain_feedback_expectation());
112 $this->check_step_count(2);
113
114 // Finish the attempt.
115 $this->quba->finish_all_questions();
116
117 // Verify.
118 $this->check_current_state(question_state::$needsgrading);
119 $this->check_current_mark(null);
120 $this->render();
121 $this->assertRegExp('/' . preg_quote($response, '/') . '/', $this->currentoutput);
122 $this->check_current_output(
123 $this->get_contains_question_text_expectation($q),
124 $this->get_contains_general_feedback_expectation($q));
125 }
126
127 public function test_deferred_feedback_plain_text() {
128
60527d0c 129 // Create an essay question.
c0d12fc1
TH
130 $q = test_question_maker::make_question('essay', 'plain');
131 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
132
133 $prefix = $this->quba->get_field_prefix($this->slot);
134 $fieldname = $prefix . 'answer';
135 $response = "x < 1\nx > 0\nFrog & Toad were friends.";
136
137 // Check the initial state.
138 $this->check_current_state(question_state::$todo);
139 $this->check_current_mark(null);
140 $this->render();
141 $this->check_contains_textarea('answer', '');
142 $this->check_current_output(
143 $this->get_contains_question_text_expectation($q),
144 $this->get_does_not_contain_feedback_expectation());
145 $this->check_step_count(1);
146
147 // Save a response.
148 $this->quba->process_all_actions(null, array(
149 'slots' => $this->slot,
150 $fieldname => $response,
151 $fieldname . 'format' => FORMAT_HTML,
152 $prefix . ':sequencecheck' => '1',
153 ));
154
155 // Verify.
156 $this->check_current_state(question_state::$complete);
157 $this->check_current_mark(null);
158 $this->check_step_count(2);
159 $this->render();
160 $this->check_contains_textarea('answer', $response);
161 $this->check_current_output(
162 $this->get_contains_question_text_expectation($q),
163 $this->get_does_not_contain_feedback_expectation());
164 $this->check_step_count(2);
165
166 // Finish the attempt.
167 $this->quba->finish_all_questions();
168
169 // Verify.
170 $this->check_current_state(question_state::$needsgrading);
171 $this->check_current_mark(null);
172 $this->render();
173 $this->assertRegExp('/' . preg_quote(s($response), '/') . '/', $this->currentoutput);
174 $this->check_current_output(
175 $this->get_contains_question_text_expectation($q),
176 $this->get_contains_general_feedback_expectation($q));
177 }
60527d0c
JMV
178
179 public function test_responsetemplate() {
180
181 // Create an essay question.
182 $q = test_question_maker::make_question('essay', 'responsetemplate');
183 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
184
185 $prefix = $this->quba->get_field_prefix($this->slot);
186 $fieldname = $prefix . 'answer';
187
188 // Check the initial state.
189 $this->check_current_state(question_state::$todo);
190 $this->check_current_mark(null);
191 $this->render();
192 $this->check_contains_textarea('answer', 'Once upon a time');
193 $this->check_current_output(
194 $this->get_contains_question_text_expectation($q),
195 $this->get_does_not_contain_feedback_expectation());
196 $this->check_step_count(1);
197
198 // Save.
199 $this->quba->process_all_actions(null, array(
200 'slots' => $this->slot,
201 $fieldname => 'Once upon a time there was a little green frog.',
202 $fieldname . 'format' => FORMAT_HTML,
203 $prefix . ':sequencecheck' => '1',
204 ));
205
206 // Verify.
207 $this->check_current_state(question_state::$complete);
208 $this->check_current_mark(null);
209 $this->check_step_count(2);
210 $this->render();
211 $this->check_contains_textarea('answer', 'Once upon a time there was a little green frog.');
212 $this->check_current_output(
213 $this->get_contains_question_text_expectation($q),
214 $this->get_does_not_contain_feedback_expectation());
215 $this->check_step_count(2);
216
217 // Finish the attempt.
218 $this->quba->finish_all_questions();
219
220 // Verify.
221 $this->check_current_state(question_state::$needsgrading);
222 $this->check_current_mark(null);
223 $this->render();
224 $this->assertRegExp('/' . preg_quote(s('Once upon a time there was a little green frog.'), '/') . '/', $this->currentoutput);
225 $this->check_current_output(
226 $this->get_contains_question_text_expectation($q),
227 $this->get_contains_general_feedback_expectation($q));
228 }
afb1b3d0
TH
229
230 public function test_deferred_feedback_html_editor_with_files_attempt_on_last() {
231 global $CFG, $USER;
232
233 $this->resetAfterTest(true);
234 $this->setAdminUser();
235 $usercontextid = context_user::instance($USER->id)->id;
236 $fs = get_file_storage();
237
238 // Create an essay question in the DB.
239 $generator = $this->getDataGenerator()->get_plugin_generator('core_question');
240 $cat = $generator->create_question_category();
241 $question = $generator->create_question('essay', 'editorfilepicker', array('category' => $cat->id));
242
243 // Start attempt at the question.
244 $q = question_bank::load_question($question->id);
245 $this->start_attempt_at_question($q, 'deferredfeedback', 1);
246
247 $this->check_current_state(question_state::$todo);
248 $this->check_current_mark(null);
249 $this->check_step_count(1);
250
251 // Process a response and check the expected result.
252 // First we need to get the draft item ids.
253 $this->render();
254 if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
255 throw new coding_exception('Editor draft item id not found.');
256 }
257 $editordraftid = $matches[1];
258 if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
259 throw new coding_exception('File manager draft item id not found.');
260 }
261 $attachementsdraftid = $matches[1];
262
263 $this->save_file_to_draft_area($usercontextid, $editordraftid, 'smile.txt', ':-)');
264 $this->save_file_to_draft_area($usercontextid, $attachementsdraftid, 'greeting.txt', 'Hello world!');
265 $this->process_submission(array(
266 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
267 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
268 '" alt="smile">.',
269 'answerformat' => FORMAT_HTML,
270 'answer:itemid' => $editordraftid,
271 'attachments' => $attachementsdraftid));
272
273 $this->check_current_state(question_state::$complete);
274 $this->check_current_mark(null);
275 $this->check_step_count(2);
276 $this->save_quba();
277
278 // Save the same response again, and verify no new step is created.
279 $this->load_quba();
280
281 $this->render();
282 if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
283 throw new coding_exception('Editor draft item id not found.');
284 }
285 $editordraftid = $matches[1];
286 if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
287 throw new coding_exception('File manager draft item id not found.');
288 }
289 $attachementsdraftid = $matches[1];
290
291 $this->process_submission(array(
292 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
293 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
294 '" alt="smile">.',
295 'answerformat' => FORMAT_HTML,
296 'answer:itemid' => $editordraftid,
297 'attachments' => $attachementsdraftid));
298
299 $this->check_current_state(question_state::$complete);
300 $this->check_current_mark(null);
301 $this->check_step_count(2);
302
303 // Now submit all and finish.
304 $this->finish();
305 $this->check_current_state(question_state::$needsgrading);
306 $this->check_current_mark(null);
307 $this->check_step_count(3);
308 $this->save_quba();
309
310 // Now start a new attempt based on the old one.
311 $this->load_quba();
312 $oldqa = $this->get_question_attempt();
313
314 $q = question_bank::load_question($question->id);
315 $this->quba = question_engine::make_questions_usage_by_activity('unit_test',
316 context_system::instance());
317 $this->quba->set_preferred_behaviour('deferredfeedback');
318 $this->slot = $this->quba->add_question($q, 1);
319 $this->quba->start_question_based_on($this->slot, $oldqa);
320
321 $this->check_current_state(question_state::$complete);
322 $this->check_current_mark(null);
323 $this->check_step_count(1);
324 $this->save_quba();
325
326 // Now save the same response again, and ensure that a new step is not created.
327 $this->load_quba();
328
329 $this->render();
330 if (!preg_match('/env=editor&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
331 throw new coding_exception('Editor draft item id not found.');
332 }
333 $editordraftid = $matches[1];
334 if (!preg_match('/env=filemanager&amp;action=browse&amp;.*?itemid=(\d+)&amp;/', $this->currentoutput, $matches)) {
335 throw new coding_exception('File manager draft item id not found.');
336 }
337 $attachementsdraftid = $matches[1];
338
339 $this->process_submission(array(
340 'answer' => 'Here is a picture: <img src="' . $CFG->wwwroot .
341 "/draftfile.php/{$usercontextid}/user/draft/{$editordraftid}/smile.txt" .
342 '" alt="smile">.',
343 'answerformat' => FORMAT_HTML,
344 'answer:itemid' => $editordraftid,
345 'attachments' => $attachementsdraftid));
346
347 $this->check_current_state(question_state::$complete);
348 $this->check_current_mark(null);
349 $this->check_step_count(1);
350 }
c0d12fc1 351}