MDL-47494 ddimageortext: Fix drag and drop on Android touch devices. #85108
[moodle.git] / question / type / ddimageortext / tests / walkthrough_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 the drag-and-drop onto image question type.
19  *
20  * @package   qtype_ddimageortext
21  * @copyright 2010 The Open University
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
30 require_once($CFG->dirroot . '/question/type/ddimageortext/tests/helper.php');
33 /**
34  * Unit tests for the drag-and-drop onto image question type.
35  *
36  * @copyright 2010 The Open University
37  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class qtype_ddimageortext_walkthrough_test extends qbehaviour_walkthrough_test_base {
41     /**
42      * Get an expectation that the output contains an item ready to drag.
43      * @param int $dragitemno the item number.
44      * @param int $choice which choice this is.
45      * @param int $group which drag group it belongs to.
46      * @return question_contains_tag_with_attributes the required expectation.
47      */
48     protected function get_contains_drag_image_home_expectation($dragitemno, $choice, $group) {
49         $class = 'group' . $group;
50         $class .= ' draghome dragitemhomes' . $dragitemno. ' choice'.$choice.' yui3-cssfonts';
52         $expectedattrs = array();
53         $expectedattrs['class'] = $class;
55         return new question_contains_tag_with_attributes('div', $expectedattrs);
56     }
58     public function test_interactive_behaviour() {
60         // Create a drag-and-drop question.
61         $dd = test_question_maker::make_question('ddimageortext');
62         $dd->hints = array(
63             new question_hint_with_parts(13, 'This is the first hint.', FORMAT_HTML, false, false),
64             new question_hint_with_parts(14, 'This is the second hint.', FORMAT_HTML, true, true),
65         );
66         $dd->shufflechoices = false;
67         $this->start_attempt_at_question($dd, 'interactive', 12);
69         // Check the initial state.
70         $this->check_current_state(question_state::$todo);
71         $this->check_current_mark(null);
73         $this->check_current_output(
74             $this->get_contains_drag_image_home_expectation(1, 1, 1),
75             $this->get_contains_drag_image_home_expectation(2, 2, 1),
76             $this->get_contains_drag_image_home_expectation(3, 1, 2),
77             $this->get_contains_drag_image_home_expectation(4, 2, 2),
78             $this->get_contains_hidden_expectation(
79                 $this->quba->get_field_prefix($this->slot) . 'p1'),
80             $this->get_contains_hidden_expectation(
81                 $this->quba->get_field_prefix($this->slot) . 'p2'),
82             $this->get_contains_hidden_expectation(
83                 $this->quba->get_field_prefix($this->slot) . 'p3'),
84             $this->get_contains_hidden_expectation(
85                 $this->quba->get_field_prefix($this->slot) . 'p4'),
86             $this->get_contains_submit_button_expectation(true),
87             $this->get_does_not_contain_feedback_expectation(),
88             $this->get_tries_remaining_expectation(3),
89             $this->get_no_hint_visible_expectation());
91         // Save the wrong answer.
92         $this->process_submission(array('p1' => '2', 'p2' => '1', 'p3' => '2', 'p4' => '1'));
93         // Verify.
94         $this->check_current_state(question_state::$todo);
95         $this->check_current_mark(null);
97         $this->check_current_output(
98             $this->get_contains_drag_image_home_expectation(1, 1, 1),
99             $this->get_contains_drag_image_home_expectation(2, 2, 1),
100             $this->get_contains_drag_image_home_expectation(3, 1, 2),
101             $this->get_contains_drag_image_home_expectation(4, 2, 2),
102             $this->get_contains_hidden_expectation(
103                 $this->quba->get_field_prefix($this->slot) . 'p1', 2),
104             $this->get_contains_hidden_expectation(
105                 $this->quba->get_field_prefix($this->slot) . 'p2', 1),
106             $this->get_contains_hidden_expectation(
107                 $this->quba->get_field_prefix($this->slot) . 'p3', 2),
108             $this->get_contains_hidden_expectation(
109                 $this->quba->get_field_prefix($this->slot) . 'p4', 1),
110             $this->get_contains_submit_button_expectation(true),
111             $this->get_does_not_contain_feedback_expectation(),
112             $this->get_tries_remaining_expectation(3),
113             $this->get_no_hint_visible_expectation());
114         // Submit the wrong answer.
115         $this->process_submission(
116             array('p1' => '2', 'p2' => '1', 'p3' => '2', 'p4' => '1', '-submit' => 1));
118         // Verify.
119         $this->check_current_state(question_state::$todo);
120         $this->check_current_mark(null);
121         $this->check_current_output(
122             $this->get_contains_drag_image_home_expectation(1, 1, 1),
123             $this->get_contains_drag_image_home_expectation(2, 2, 1),
124             $this->get_contains_drag_image_home_expectation(3, 1, 2),
125             $this->get_contains_drag_image_home_expectation(4, 2, 2),
126             $this->get_contains_hidden_expectation(
127                 $this->quba->get_field_prefix($this->slot) . 'p1', 2),
128             $this->get_contains_hidden_expectation(
129                 $this->quba->get_field_prefix($this->slot) . 'p2', 1),
130             $this->get_contains_hidden_expectation(
131                 $this->quba->get_field_prefix($this->slot) . 'p3', 2),
132             $this->get_contains_hidden_expectation(
133                 $this->quba->get_field_prefix($this->slot) . 'p4', 1),
134             $this->get_contains_try_again_button_expectation(true),
135             new question_pattern_expectation('/' .
136                 preg_quote(get_string('notcomplete', 'qbehaviour_interactive'), '/') . '/'),
137             $this->get_contains_hint_expectation('This is the first hint'));
139         // Do try again.
140         $this->process_submission(array('-tryagain' => 1));
142         // Verify.
143         $this->check_current_state(question_state::$todo);
144         $this->check_current_mark(null);
146         $this->check_current_output(
147             $this->get_contains_drag_image_home_expectation(1, 1, 1),
148             $this->get_contains_drag_image_home_expectation(2, 2, 1),
149             $this->get_contains_drag_image_home_expectation(3, 1, 2),
150             $this->get_contains_drag_image_home_expectation(4, 2, 2),
151             $this->get_contains_hidden_expectation(
152                 $this->quba->get_field_prefix($this->slot) . 'p1', '2'),
153             $this->get_contains_hidden_expectation(
154                 $this->quba->get_field_prefix($this->slot) . 'p2', '1'),
155             $this->get_contains_hidden_expectation(
156                 $this->quba->get_field_prefix($this->slot) . 'p3', '2'),
157             $this->get_contains_hidden_expectation(
158                 $this->quba->get_field_prefix($this->slot) . 'p4', '1'),
159             $this->get_contains_submit_button_expectation(true),
160             $this->get_does_not_contain_correctness_expectation(),
161             $this->get_does_not_contain_feedback_expectation(),
162             $this->get_tries_remaining_expectation(2),
163             $this->get_no_hint_visible_expectation());
165         // Submit the right answer.
166         $this->process_submission(
167             array('p1' => '1', 'p2' => '2', 'p3' => '1', 'p4' => '2', '-submit' => 1));
169         // Verify.
170         $this->check_current_state(question_state::$gradedright);
171         $this->check_current_mark(8);
172         $this->check_current_output(
173             $this->get_contains_drag_image_home_expectation(1, 1, 1),
174             $this->get_contains_drag_image_home_expectation(2, 2, 1),
175             $this->get_contains_drag_image_home_expectation(3, 1, 2),
176             $this->get_contains_drag_image_home_expectation(4, 2, 2),
177             $this->get_contains_hidden_expectation(
178                 $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
179             $this->get_contains_hidden_expectation(
180                 $this->quba->get_field_prefix($this->slot) . 'p2', '2'),
181             $this->get_contains_hidden_expectation(
182                 $this->quba->get_field_prefix($this->slot) . 'p3', '1'),
183             $this->get_contains_hidden_expectation(
184                 $this->quba->get_field_prefix($this->slot) . 'p4', '2'),
185             $this->get_contains_submit_button_expectation(false),
186             $this->get_contains_correct_expectation(),
187             $this->get_no_hint_visible_expectation());
189         // Check regrading does not mess anything up.
190         $this->quba->regrade_all_questions();
192         // Verify.
193         $this->check_current_state(question_state::$gradedright);
194         $this->check_current_mark(8);
195     }
197     public function test_deferred_feedback() {
199         // Create a drag-and-drop question.
200         $dd = test_question_maker::make_question('ddimageortext');
201         $dd->shufflechoices = false;
202         $this->start_attempt_at_question($dd, 'deferredfeedback', 12);
204         // Check the initial state.
205         $this->check_current_state(question_state::$todo);
206         $this->check_current_mark(null);
208         $this->check_current_output(
209             $this->get_contains_drag_image_home_expectation(1, 1, 1),
210             $this->get_contains_drag_image_home_expectation(2, 2, 1),
211             $this->get_contains_drag_image_home_expectation(3, 1, 2),
212             $this->get_contains_drag_image_home_expectation(4, 2, 2),
213             $this->get_contains_hidden_expectation(
214                 $this->quba->get_field_prefix($this->slot) . 'p1'),
215             $this->get_contains_hidden_expectation(
216                 $this->quba->get_field_prefix($this->slot) . 'p2'),
217             $this->get_contains_hidden_expectation(
218                 $this->quba->get_field_prefix($this->slot) . 'p3'),
219             $this->get_contains_hidden_expectation(
220                 $this->quba->get_field_prefix($this->slot) . 'p4'),
221             $this->get_does_not_contain_feedback_expectation());
223         // Save a partial answer.
224         $this->process_submission(array('p1' => '2', 'p2' => '1'));
225         // Verify.
226         $this->check_current_state(question_state::$invalid);
227         $this->check_current_mark(null);
229         $this->check_current_output(
230             $this->get_contains_drag_image_home_expectation(1, 1, 1),
231             $this->get_contains_drag_image_home_expectation(2, 2, 1),
232             $this->get_contains_drag_image_home_expectation(3, 1, 2),
233             $this->get_contains_drag_image_home_expectation(4, 2, 2),
234             $this->get_contains_hidden_expectation(
235                 $this->quba->get_field_prefix($this->slot) . 'p1', 2),
236             $this->get_contains_hidden_expectation(
237                 $this->quba->get_field_prefix($this->slot) . 'p2', 1),
238             $this->get_contains_hidden_expectation(
239                 $this->quba->get_field_prefix($this->slot) . 'p3', ''),
240             $this->get_contains_hidden_expectation(
241                 $this->quba->get_field_prefix($this->slot) . 'p4', ''),
242             $this->get_does_not_contain_correctness_expectation(),
243             $this->get_does_not_contain_feedback_expectation());
244         // Save the right answer.
245         $this->process_submission(
246             array('p1' => '1', 'p2' => '2', 'p3' => '1', 'p4' => '2'));
248         // Verify.
249         $this->check_current_state(question_state::$complete);
250         $this->check_current_mark(null);
251         $this->check_current_output(
252             $this->get_contains_drag_image_home_expectation(1, 1, 1),
253             $this->get_contains_drag_image_home_expectation(2, 2, 1),
254             $this->get_contains_drag_image_home_expectation(3, 1, 2),
255             $this->get_contains_drag_image_home_expectation(4, 2, 2),
256             $this->get_contains_hidden_expectation(
257                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
258             $this->get_contains_hidden_expectation(
259                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
260             $this->get_contains_hidden_expectation(
261                 $this->quba->get_field_prefix($this->slot) . 'p3', 1),
262             $this->get_contains_hidden_expectation(
263                 $this->quba->get_field_prefix($this->slot) . 'p4', 2),
264             $this->get_does_not_contain_correctness_expectation(),
265             $this->get_does_not_contain_feedback_expectation());
267         // Finish the attempt.
268         $this->quba->finish_all_questions();
270         // Verify.
271         $this->check_current_state(question_state::$gradedright);
272         $this->check_current_mark(12);
274         $this->check_current_output(
275             $this->get_contains_drag_image_home_expectation(1, 1, 1),
276             $this->get_contains_drag_image_home_expectation(2, 2, 1),
277             $this->get_contains_drag_image_home_expectation(3, 1, 2),
278             $this->get_contains_drag_image_home_expectation(4, 2, 2),
279             $this->get_contains_hidden_expectation(
280                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
281             $this->get_contains_hidden_expectation(
282                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
283             $this->get_contains_hidden_expectation(
284                 $this->quba->get_field_prefix($this->slot) . 'p3', 1),
285             $this->get_contains_hidden_expectation(
286                 $this->quba->get_field_prefix($this->slot) . 'p4', 2),
287             $this->get_contains_correct_expectation());
289         // Change the right answer a bit.
290         $dd->rightchoices[2] = 1;
292         // Check regrading does not mess anything up.
293         $this->quba->regrade_all_questions();
295         // Verify.
296         $this->check_current_state(question_state::$gradedpartial);
297         $this->check_current_mark(9);
298     }
300     public function test_deferred_feedback_unanswered() {
302         // Create a drag-and-drop question.
303         $dd = test_question_maker::make_question('ddimageortext');
304         $dd->shufflechoices = false;
305         $this->start_attempt_at_question($dd, 'deferredfeedback', 12);
307         // Check the initial state.
308         $this->check_current_state(question_state::$todo);
309         $this->check_current_mark(null);
310         $this->check_current_output(
311             $this->get_contains_drag_image_home_expectation(1, 1, 1),
312             $this->get_contains_drag_image_home_expectation(2, 2, 1),
313             $this->get_contains_drag_image_home_expectation(3, 1, 2),
314             $this->get_contains_drag_image_home_expectation(4, 2, 2),
315             $this->get_contains_hidden_expectation(
316                 $this->quba->get_field_prefix($this->slot) . 'p1'),
317             $this->get_contains_hidden_expectation(
318                 $this->quba->get_field_prefix($this->slot) . 'p2'),
319             $this->get_contains_hidden_expectation(
320                 $this->quba->get_field_prefix($this->slot) . 'p3'),
321             $this->get_contains_hidden_expectation(
322                 $this->quba->get_field_prefix($this->slot) . 'p4'),
323             $this->get_does_not_contain_correctness_expectation(),
324             $this->get_does_not_contain_feedback_expectation());
325         $this->check_step_count(1);
327         // Save a blank response.
328         $this->process_submission(array('p1' => '', 'p2' => '', 'p3' => '', 'p4' => ''));
330         // Verify.
331         $this->check_current_state(question_state::$todo);
332         $this->check_current_mark(null);
333         $this->check_current_output(
334             $this->get_contains_drag_image_home_expectation(1, 1, 1),
335             $this->get_contains_drag_image_home_expectation(2, 2, 1),
336             $this->get_contains_drag_image_home_expectation(3, 1, 2),
337             $this->get_contains_drag_image_home_expectation(4, 2, 2),
338             $this->get_contains_hidden_expectation(
339                 $this->quba->get_field_prefix($this->slot) . 'p1', ''),
340             $this->get_contains_hidden_expectation(
341                 $this->quba->get_field_prefix($this->slot) . 'p2', ''),
342             $this->get_contains_hidden_expectation(
343                 $this->quba->get_field_prefix($this->slot) . 'p3', ''),
344             $this->get_contains_hidden_expectation(
345                 $this->quba->get_field_prefix($this->slot) . 'p4', ''),
346             $this->get_does_not_contain_correctness_expectation(),
347             $this->get_does_not_contain_feedback_expectation());
348         $this->check_step_count(1);
350         // Finish the attempt.
351         $this->quba->finish_all_questions();
353         // Verify.
354         $this->check_current_state(question_state::$gaveup);
355         $this->check_current_mark(null);
356         $this->check_current_output(
357             $this->get_contains_drag_image_home_expectation(1, 1, 1),
358             $this->get_contains_drag_image_home_expectation(2, 2, 1),
359             $this->get_contains_drag_image_home_expectation(3, 1, 2),
360             $this->get_contains_drag_image_home_expectation(4, 2, 2));
361     }
363     public function test_deferred_feedback_partial_answer() {
365         // Create a drag-and-drop question.
366         $dd = test_question_maker::make_question('ddimageortext');
367         $dd->shufflechoices = false;
368         $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
370         // Check the initial state.
371         $this->check_current_state(question_state::$todo);
372         $this->check_current_mark(null);
373         $this->check_current_output(
374             $this->get_contains_drag_image_home_expectation(1, 1, 1),
375             $this->get_contains_drag_image_home_expectation(2, 2, 1),
376             $this->get_contains_drag_image_home_expectation(3, 1, 2),
377             $this->get_contains_drag_image_home_expectation(4, 2, 2),
378             $this->get_contains_hidden_expectation(
379                 $this->quba->get_field_prefix($this->slot) . 'p1'),
380             $this->get_contains_hidden_expectation(
381                 $this->quba->get_field_prefix($this->slot) . 'p2'),
382             $this->get_contains_hidden_expectation(
383                 $this->quba->get_field_prefix($this->slot) . 'p3'),
384             $this->get_contains_hidden_expectation(
385                 $this->quba->get_field_prefix($this->slot) . 'p4'),
386             $this->get_does_not_contain_correctness_expectation(),
387             $this->get_does_not_contain_feedback_expectation());
389         // Save a partial response.
390         $this->process_submission(array('p1' => '1', 'p2' => '2', 'p3' => '', 'p4' => ''));
392         // Verify.
393         $this->check_current_state(question_state::$invalid);
394         $this->check_current_mark(null);
395         $this->check_current_output(
396             $this->get_contains_drag_image_home_expectation(1, 1, 1),
397             $this->get_contains_drag_image_home_expectation(2, 2, 1),
398             $this->get_contains_drag_image_home_expectation(3, 1, 2),
399             $this->get_contains_drag_image_home_expectation(4, 2, 2),
400             $this->get_contains_hidden_expectation(
401                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
402             $this->get_contains_hidden_expectation(
403                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
404             $this->get_contains_hidden_expectation(
405                 $this->quba->get_field_prefix($this->slot) . 'p3', 0),
406             $this->get_contains_hidden_expectation(
407                 $this->quba->get_field_prefix($this->slot) . 'p4', 0),
408             $this->get_does_not_contain_correctness_expectation(),
409             $this->get_does_not_contain_feedback_expectation());
411         // Finish the attempt.
412         $this->quba->finish_all_questions();
414         // Verify.
415         $this->check_current_state(question_state::$gradedpartial);
416         $this->check_current_mark(1.5);
417         $this->check_current_output(
418             $this->get_contains_drag_image_home_expectation(1, 1, 1),
419             $this->get_contains_drag_image_home_expectation(2, 2, 1),
420             $this->get_contains_drag_image_home_expectation(3, 1, 2),
421             $this->get_contains_drag_image_home_expectation(4, 2, 2),
422             $this->get_contains_partcorrect_expectation());
423     }
425     public function test_interactive_grading() {
427         // Create a drag-and-drop question.
428         $dd = test_question_maker::make_question('ddimageortext');
429         $dd->hints = array(
430             new question_hint_with_parts(1, 'This is the first hint.',
431                 FORMAT_MOODLE, true, true),
432             new question_hint_with_parts(2, 'This is the second hint.',
433                 FORMAT_MOODLE, true, true),
434         );
435         $dd->shufflechoices = false;
436         $this->start_attempt_at_question($dd, 'interactive', 12);
438         // Check the initial state.
439         $this->check_current_state(question_state::$todo);
440         $this->check_current_mark(null);
441         $this->assertEquals('interactivecountback',
442             $this->quba->get_question_attempt($this->slot)->get_behaviour_name());
443         $this->check_current_output(
444             $this->get_contains_drag_image_home_expectation(1, 1, 1),
445             $this->get_contains_drag_image_home_expectation(2, 2, 1),
446             $this->get_contains_drag_image_home_expectation(3, 1, 2),
447             $this->get_contains_drag_image_home_expectation(4, 2, 2),
448             $this->get_contains_hidden_expectation(
449                 $this->quba->get_field_prefix($this->slot) . 'p1'),
450             $this->get_contains_hidden_expectation(
451                 $this->quba->get_field_prefix($this->slot) . 'p2'),
452             $this->get_contains_hidden_expectation(
453                 $this->quba->get_field_prefix($this->slot) . 'p3'),
454             $this->get_contains_hidden_expectation(
455                 $this->quba->get_field_prefix($this->slot) . 'p4'),
456             $this->get_contains_submit_button_expectation(true),
457             $this->get_does_not_contain_feedback_expectation(),
458             $this->get_tries_remaining_expectation(3),
459             $this->get_does_not_contain_num_parts_correct(),
460             $this->get_no_hint_visible_expectation());
462         // Submit an response with the first two parts right.
463         $this->process_submission(
464             array('p1' => '1', 'p2' => '2', 'p3' => '2', 'p4' => '1', '-submit' => 1));
466         // Verify.
467         $this->check_current_state(question_state::$todo);
468         $this->check_current_mark(null);
469         $this->check_current_output(
470             $this->get_contains_drag_image_home_expectation(1, 1, 1),
471             $this->get_contains_drag_image_home_expectation(2, 2, 1),
472             $this->get_contains_drag_image_home_expectation(3, 1, 2),
473             $this->get_contains_drag_image_home_expectation(4, 2, 2),
474             $this->get_contains_submit_button_expectation(false),
475             $this->get_contains_try_again_button_expectation(true),
476             $this->get_does_not_contain_correctness_expectation(),
477             new question_pattern_expectation('/' .
478                 preg_quote(get_string('notcomplete', 'qbehaviour_interactive'), '/') . '/'),
479             $this->get_contains_hint_expectation('This is the first hint'),
480             $this->get_contains_num_parts_correct(2),
481             $this->get_contains_standard_partiallycorrect_combined_feedback_expectation(),
482             $this->get_contains_hidden_expectation(
483                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
484             $this->get_contains_hidden_expectation(
485                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
486             $this->get_contains_hidden_expectation(
487                 $this->quba->get_field_prefix($this->slot) . 'p3', 2),
488             $this->get_contains_hidden_expectation(
489                 $this->quba->get_field_prefix($this->slot) . 'p4', 1));
491         // Check that extract responses will return the reset data.
492         $prefix = $this->quba->get_field_prefix($this->slot);
493         $this->assertEquals(array('p1' => '1', 'p2' => '2'),
494             $this->quba->extract_responses($this->slot,
495                 array($prefix . 'p1' => '1', $prefix . 'p2' => '2', '-tryagain' => 1)));
497         // Do try again.
498         // keys p3 and p4 are extra hidden fields to clear data.
499         $this->process_submission(
500             array('p1' => '1', 'p2' => '2', 'p3' => '', 'p4' => '', '-tryagain' => 1));
502         // Verify.
503         $this->check_current_state(question_state::$todo);
504         $this->check_current_mark(null);
505         $this->check_current_output(
506             $this->get_contains_drag_image_home_expectation(1, 1, 1),
507             $this->get_contains_drag_image_home_expectation(2, 2, 1),
508             $this->get_contains_drag_image_home_expectation(3, 1, 2),
509             $this->get_contains_drag_image_home_expectation(4, 2, 2),
510             $this->get_contains_hidden_expectation(
511                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
512             $this->get_contains_hidden_expectation(
513                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
514             $this->get_contains_hidden_expectation(
515                 $this->quba->get_field_prefix($this->slot) . 'p3', 0),
516             $this->get_contains_hidden_expectation(
517                 $this->quba->get_field_prefix($this->slot) . 'p4', 0),
518             $this->get_contains_submit_button_expectation(true),
519             $this->get_does_not_contain_try_again_button_expectation(),
520             $this->get_does_not_contain_correctness_expectation(),
521             $this->get_does_not_contain_feedback_expectation(),
522             $this->get_tries_remaining_expectation(2),
523             $this->get_no_hint_visible_expectation());
525         // Submit an response with the first and last parts right.
526         $this->process_submission(
527             array('p1' => '1', 'p2' => '1', 'p3' => '2', 'p4' => '2', '-submit' => 1));
529         // Verify.
530         $this->check_current_state(question_state::$todo);
531         $this->check_current_mark(null);
532         $this->check_current_output(
533             $this->get_contains_drag_image_home_expectation(1, 1, 1),
534             $this->get_contains_drag_image_home_expectation(2, 2, 1),
535             $this->get_contains_drag_image_home_expectation(3, 1, 2),
536             $this->get_contains_drag_image_home_expectation(4, 2, 2),
537             $this->get_contains_submit_button_expectation(false),
538             $this->get_contains_try_again_button_expectation(true),
539             $this->get_does_not_contain_correctness_expectation(),
540             new question_pattern_expectation('/' .
541                 preg_quote(get_string('notcomplete', 'qbehaviour_interactive'), '/') . '/'),
542             $this->get_contains_hint_expectation('This is the second hint'),
543             $this->get_contains_num_parts_correct(2),
544             $this->get_contains_standard_partiallycorrect_combined_feedback_expectation(),
545             $this->get_contains_hidden_expectation(
546                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
547             $this->get_contains_hidden_expectation(
548                 $this->quba->get_field_prefix($this->slot) . 'p2', 1),
549             $this->get_contains_hidden_expectation(
550                 $this->quba->get_field_prefix($this->slot) . 'p3', 2),
551             $this->get_contains_hidden_expectation(
552                 $this->quba->get_field_prefix($this->slot) . 'p4', 2));
554         // Do try again.
555         $this->process_submission(
556             array('p1' => '1', 'p2' => '', 'p3' => '', 'p4' => '2', '-tryagain' => 1));
558         // Verify.
559         $this->check_current_state(question_state::$todo);
560         $this->check_current_mark(null);
561         $this->check_current_output(
562             $this->get_contains_drag_image_home_expectation(1, 1, 1),
563             $this->get_contains_drag_image_home_expectation(2, 2, 1),
564             $this->get_contains_drag_image_home_expectation(3, 1, 2),
565             $this->get_contains_drag_image_home_expectation(4, 2, 2),
566             $this->get_contains_hidden_expectation(
567                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
568             $this->get_contains_hidden_expectation(
569                 $this->quba->get_field_prefix($this->slot) . 'p2', 0),
570             $this->get_contains_hidden_expectation(
571                 $this->quba->get_field_prefix($this->slot) . 'p3', 0),
572             $this->get_contains_hidden_expectation(
573                 $this->quba->get_field_prefix($this->slot) . 'p4', 2),
574             $this->get_contains_submit_button_expectation(true),
575             $this->get_does_not_contain_try_again_button_expectation(),
576             $this->get_does_not_contain_correctness_expectation(),
577             $this->get_does_not_contain_feedback_expectation(),
578             $this->get_tries_remaining_expectation(1),
579             $this->get_no_hint_visible_expectation());
581         // Submit the right answer.
582         $this->process_submission(
583             array('p1' => '1', 'p2' => '2', 'p3' => '1', 'p4' => '2', '-submit' => 1));
585         // Verify.
586         $this->check_current_state(question_state::$gradedright);
587         $this->check_current_mark(7);
588         $this->check_current_output(
589             $this->get_contains_drag_image_home_expectation(1, 1, 1),
590             $this->get_contains_drag_image_home_expectation(2, 2, 1),
591             $this->get_contains_drag_image_home_expectation(3, 1, 2),
592             $this->get_contains_drag_image_home_expectation(4, 2, 2),
593             $this->get_contains_hidden_expectation(
594                 $this->quba->get_field_prefix($this->slot) . 'p1', 1),
595             $this->get_contains_hidden_expectation(
596                 $this->quba->get_field_prefix($this->slot) . 'p2', 2),
597             $this->get_contains_hidden_expectation(
598                 $this->quba->get_field_prefix($this->slot) . 'p3', 1),
599             $this->get_contains_hidden_expectation(
600                 $this->quba->get_field_prefix($this->slot) . 'p4', 2),
601             $this->get_contains_submit_button_expectation(false),
602             $this->get_does_not_contain_try_again_button_expectation(),
603             $this->get_contains_correct_expectation(),
604             $this->get_no_hint_visible_expectation(),
605             $this->get_does_not_contain_num_parts_correct(),
606             $this->get_contains_standard_correct_combined_feedback_expectation());
607     }
609     public function test_interactive_correct_no_submit() {
611         // Create a drag-and-drop question.
612         $dd = test_question_maker::make_question('ddimageortext');
613         $dd->hints = array(
614             new question_hint_with_parts(23, 'This is the first hint.',
615                 FORMAT_MOODLE, false, false),
616             new question_hint_with_parts(24, 'This is the second hint.',
617                 FORMAT_MOODLE, true, true),
618         );
619         $dd->shufflechoices = false;
620         $this->start_attempt_at_question($dd, 'interactive', 3);
622         // Check the initial state.
623         $this->check_current_state(question_state::$todo);
624         $this->check_current_mark(null);
625         $this->check_current_output(
626             $this->get_contains_drag_image_home_expectation(1, 1, 1),
627             $this->get_contains_drag_image_home_expectation(2, 2, 1),
628             $this->get_contains_drag_image_home_expectation(3, 1, 2),
629             $this->get_contains_drag_image_home_expectation(4, 2, 2),
630             $this->get_contains_hidden_expectation(
631                 $this->quba->get_field_prefix($this->slot) . 'p1'),
632             $this->get_contains_hidden_expectation(
633                 $this->quba->get_field_prefix($this->slot) . 'p2'),
634             $this->get_contains_hidden_expectation(
635                 $this->quba->get_field_prefix($this->slot) . 'p3'),
636             $this->get_contains_hidden_expectation(
637                 $this->quba->get_field_prefix($this->slot) . 'p4'),
638             $this->get_contains_submit_button_expectation(true),
639             $this->get_does_not_contain_feedback_expectation(),
640             $this->get_tries_remaining_expectation(3),
641             $this->get_no_hint_visible_expectation());
643         // Save the right answer.
644         $this->process_submission(array('p1' => '1', 'p2' => '2', 'p3' => '1', 'p4' => '2'));
646         // Finish the attempt without clicking check.
647         $this->quba->finish_all_questions();
649         // Verify.
650         $this->check_current_state(question_state::$gradedright);
651         $this->check_current_mark(3);
652         $this->check_current_output(
653             $this->get_contains_drag_image_home_expectation(1, 1, 1),
654             $this->get_contains_drag_image_home_expectation(2, 2, 1),
655             $this->get_contains_drag_image_home_expectation(3, 1, 2),
656             $this->get_contains_drag_image_home_expectation(4, 2, 2),
657             $this->get_contains_submit_button_expectation(false),
658             $this->get_contains_correct_expectation(),
659             $this->get_no_hint_visible_expectation());
661         // Check regrading does not mess anything up.
662         $this->quba->regrade_all_questions();
664         // Verify.
665         $this->check_current_state(question_state::$gradedright);
666         $this->check_current_mark(3);
667     }
669     public function test_interactive_partial_no_submit() {
671         // Create a drag-and-drop question.
672         $dd = test_question_maker::make_question('ddimageortext');
673         $dd->hints = array(
674             new question_hint_with_parts(23, 'This is the first hint.',
675                 FORMAT_MOODLE, false, false),
676             new question_hint_with_parts(24, 'This is the second hint.',
677                 FORMAT_MOODLE, true, true),
678         );
679         $dd->shufflechoices = false;
680         $this->start_attempt_at_question($dd, 'interactive', 4);
682         // Check the initial state.
683         $this->check_current_state(question_state::$todo);
684         $this->check_current_mark(null);
686         $this->check_current_output(
687             $this->get_contains_drag_image_home_expectation(1, 1, 1),
688             $this->get_contains_drag_image_home_expectation(2, 2, 1),
689             $this->get_contains_drag_image_home_expectation(3, 1, 2),
690             $this->get_contains_drag_image_home_expectation(4, 2, 2),
691             $this->get_contains_hidden_expectation(
692                 $this->quba->get_field_prefix($this->slot) . 'p1'),
693             $this->get_contains_hidden_expectation(
694                 $this->quba->get_field_prefix($this->slot) . 'p2'),
695             $this->get_contains_hidden_expectation(
696                 $this->quba->get_field_prefix($this->slot) . 'p3'),
697             $this->get_contains_hidden_expectation(
698                 $this->quba->get_field_prefix($this->slot) . 'p4'),
699             $this->get_contains_submit_button_expectation(true),
700             $this->get_does_not_contain_feedback_expectation(),
701             $this->get_tries_remaining_expectation(3),
702             $this->get_no_hint_visible_expectation());
704         // Save the a partially right answer.
705         $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '2', 'p4' => '1'));
707         // Finish the attempt without clicking check.
708         $this->quba->finish_all_questions();
710         // Verify.
711         $this->check_current_state(question_state::$gradedpartial);
712         $this->check_current_mark(1);
714         $this->check_current_output(
715             $this->get_contains_drag_image_home_expectation(1, 1, 1),
716             $this->get_contains_drag_image_home_expectation(2, 2, 1),
717             $this->get_contains_drag_image_home_expectation(3, 1, 2),
718             $this->get_contains_drag_image_home_expectation(4, 2, 2),
719             $this->get_contains_submit_button_expectation(false),
720             $this->get_contains_partcorrect_expectation(),
721             $this->get_no_hint_visible_expectation());
723         // Check regrading does not mess anything up.
724         $this->quba->regrade_all_questions();
726         // Verify.
727         $this->check_current_state(question_state::$gradedpartial);
728         $this->check_current_mark(1);
729     }
731     public function test_interactive_no_right_clears() {
733         // Create a drag-and-drop question.
734         $dd = test_question_maker::make_question('ddimageortext');
735         $dd->hints = array(
736             new question_hint_with_parts(23, 'This is the first hint.', FORMAT_MOODLE, false, true),
737             new question_hint_with_parts(24, 'This is the second hint.', FORMAT_MOODLE, true, true),
738         );
739         $dd->shufflechoices = false;
740         $this->start_attempt_at_question($dd, 'interactive', 3);
742         // Check the initial state.
743         $this->check_current_state(question_state::$todo);
744         $this->check_current_mark(null);
746         $this->check_current_output(
747             $this->get_contains_marked_out_of_summary(),
748             $this->get_contains_drag_image_home_expectation(1, 1, 1),
749             $this->get_contains_drag_image_home_expectation(2, 2, 1),
750             $this->get_contains_drag_image_home_expectation(3, 1, 2),
751             $this->get_contains_drag_image_home_expectation(4, 2, 2),
752             $this->get_contains_hidden_expectation(
753                 $this->quba->get_field_prefix($this->slot) . 'p1'),
754             $this->get_contains_hidden_expectation(
755                 $this->quba->get_field_prefix($this->slot) . 'p2'),
756             $this->get_contains_hidden_expectation(
757                 $this->quba->get_field_prefix($this->slot) . 'p3'),
758             $this->get_contains_hidden_expectation(
759                 $this->quba->get_field_prefix($this->slot) . 'p4'),
760             $this->get_contains_submit_button_expectation(true),
761             $this->get_does_not_contain_feedback_expectation(),
762             $this->get_tries_remaining_expectation(3),
763             $this->get_no_hint_visible_expectation());
765         // Save the a completely wrong answer.
766         $this->process_submission(
767             array('p1' => '2', 'p2' => '1', 'p3' => '2', 'p4' => '1', '-submit' => 1));
769         // Verify.
770         $this->check_current_state(question_state::$todo);
771         $this->check_current_mark(null);
772         $this->check_current_output(
773             $this->get_contains_marked_out_of_summary(),
774             $this->get_contains_drag_image_home_expectation(1, 1, 1),
775             $this->get_contains_drag_image_home_expectation(2, 2, 1),
776             $this->get_contains_drag_image_home_expectation(3, 1, 2),
777             $this->get_contains_drag_image_home_expectation(4, 2, 2),
778             $this->get_contains_submit_button_expectation(false),
779             $this->get_contains_hint_expectation('This is the first hint'));
781         // Do try again.
782         $this->process_submission(
783             array('p1' => '', 'p2' => '', 'p3' => '', 'p4' => '', '-tryagain' => 1));
785         // Check that all the wrong answers have been cleared.
786         $this->check_current_state(question_state::$todo);
787         $this->check_current_mark(null);
788         $this->check_current_output(
789             $this->get_contains_marked_out_of_summary(),
790             $this->get_contains_drag_image_home_expectation(1, 1, 1),
791             $this->get_contains_drag_image_home_expectation(2, 2, 1),
792             $this->get_contains_drag_image_home_expectation(3, 1, 2),
793             $this->get_contains_drag_image_home_expectation(4, 2, 2),
794             $this->get_contains_hidden_expectation(
795                 $this->quba->get_field_prefix($this->slot) . 'p1', 0),
796             $this->get_contains_hidden_expectation(
797                 $this->quba->get_field_prefix($this->slot) . 'p2', 0),
798             $this->get_contains_hidden_expectation(
799                 $this->quba->get_field_prefix($this->slot) . 'p3', 0),
800             $this->get_contains_hidden_expectation(
801                 $this->quba->get_field_prefix($this->slot) . 'p4', 0),
802             $this->get_contains_submit_button_expectation(true),
803             $this->get_does_not_contain_feedback_expectation(),
804             $this->get_tries_remaining_expectation(2),
805             $this->get_no_hint_visible_expectation());
806     }
808     public function test_display_of_right_answer_when_shuffled() {
810         // Create a drag-and-drop question.
811         $dd = test_question_maker::make_question('ddimageortext');
812         $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
814         // Check the initial state.
815         $this->check_current_state(question_state::$todo);
816         $this->check_current_mark(null);
818         $this->check_current_output(
819             $this->get_contains_hidden_expectation(
820                 $this->quba->get_field_prefix($this->slot) . 'p1'),
821             $this->get_contains_hidden_expectation(
822                 $this->quba->get_field_prefix($this->slot) . 'p2'),
823             $this->get_contains_hidden_expectation(
824                 $this->quba->get_field_prefix($this->slot) . 'p3'),
825             $this->get_contains_hidden_expectation(
826                 $this->quba->get_field_prefix($this->slot) . 'p4'),
827             $this->get_does_not_contain_feedback_expectation());
829         // Save a partial answer.
830         $this->process_submission($dd->get_correct_response());
832         // Verify.
833         $this->check_current_state(question_state::$complete);
834         $this->check_current_mark(null);
835         $this->check_current_output(
836             $this->get_contains_hidden_expectation(
837                 $this->quba->get_field_prefix($this->slot) . 'p1',
838                 $dd->get_right_choice_for(1)),
839             $this->get_contains_hidden_expectation(
840                 $this->quba->get_field_prefix($this->slot) . 'p2',
841                 $dd->get_right_choice_for(2)),
842             $this->get_contains_hidden_expectation(
843                 $this->quba->get_field_prefix($this->slot) . 'p3',
844                 $dd->get_right_choice_for(3)),
845             $this->get_contains_hidden_expectation(
846                 $this->quba->get_field_prefix($this->slot) . 'p4',
847                 $dd->get_right_choice_for(4)),
848             $this->get_does_not_contain_correctness_expectation(),
849             $this->get_does_not_contain_feedback_expectation());
851         // Finish the attempt.
852         $this->quba->finish_all_questions();
854         // Verify.
855         $this->displayoptions->rightanswer = question_display_options::VISIBLE;
856         $this->assertEquals('Drop zone 1 -> {1. quick} '.
857                 'Drop zone 2 -> {2. fox} '.
858                 'Drop zone 3 -> {3. lazy} '.
859                 'Drop zone 4 -> {4. dog}',
860             $dd->get_right_answer_summary());
861         $this->check_current_state(question_state::$gradedright);
862         $this->check_current_mark(3);
863     }