MDL-64420 qtype: gapselect unit tests unsafe
[moodle.git] / question / type / randomsamatch / 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  * This file contains tests that walks a question through the interactive
19  * behaviour.
20  *
21  * @package   qtype_randomsamatch
22  * @copyright 2013 Jean-Michel Vedrine
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
33 /**
34  * Unit tests for the randomsamatch question type.
35  *
36  * @copyright 2013 Jean-Michel Vedrine
37  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class qtype_randomsamatch_walkthrough_test extends qbehaviour_walkthrough_test_base {
41     public function test_deferred_feedback_unanswered() {
43         // Create a randomsamatch question.
44         $m = test_question_maker::make_question('randomsamatch');
45         $this->start_attempt_at_question($m, 'deferredfeedback', 4);
47         $choiceorder = $m->get_choice_order();
48         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
49         $choices = [];
50         foreach ($choiceorder as $key => $choice) {
51             $choices[$key] = $m->choices[$choice];
52         }
54         // Check the initial state.
55         $this->check_current_state(question_state::$todo);
56         $this->check_current_mark(null);
57         $this->check_current_output(
58                 $this->get_contains_question_text_expectation($m),
59                 $this->get_does_not_contain_feedback_expectation());
60         $this->check_output_contains_selectoptions(
61                 $this->get_contains_select_expectation('sub0', $choices, null, true),
62                 $this->get_contains_select_expectation('sub1', $choices, null, true),
63                 $this->get_contains_select_expectation('sub2', $choices, null, true),
64                 $this->get_contains_select_expectation('sub3', $choices, null, true));
65         $this->check_step_count(1);
67         // Save a blank response.
68         $this->process_submission(array('sub0' => '0', 'sub1' => '0',
69                 'sub2' => '0', 'sub3' => '0'));
71         // Verify.
72         $this->check_current_state(question_state::$todo);
73         $this->check_current_mark(null);
74         $this->check_current_output(
75                 $this->get_contains_question_text_expectation($m),
76                 $this->get_does_not_contain_feedback_expectation());
77         $this->check_output_contains_selectoptions(
78                 $this->get_contains_select_expectation('sub0', $choices, null, true),
79                 $this->get_contains_select_expectation('sub1', $choices, null, true),
80                 $this->get_contains_select_expectation('sub2', $choices, null, true),
81                 $this->get_contains_select_expectation('sub3', $choices, null, true));
82         $this->check_step_count(1);
84         // Finish the attempt.
85         $this->quba->finish_all_questions();
87         // Verify.
88         $this->check_current_state(question_state::$gaveup);
89         $this->check_current_mark(null);
90         $this->check_output_contains_selectoptions(
91                 $this->get_contains_select_expectation('sub0', $choices, null, false),
92                 $this->get_contains_select_expectation('sub1', $choices, null, false),
93                 $this->get_contains_select_expectation('sub2', $choices, null, false),
94                 $this->get_contains_select_expectation('sub3', $choices, null, false));
95     }
97     public function test_deferred_feedback_partial_answer() {
99         // Create a randomsamatching question.
100         $m = test_question_maker::make_question('randomsamatch');
101         $m->shufflestems = false;
102         $this->start_attempt_at_question($m, 'deferredfeedback', 4);
104         $choiceorder = $m->get_choice_order();
105         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
106         $choices = [];
107         foreach ($choiceorder as $key => $choice) {
108             $choices[$key] = $m->choices[$choice];
109         }
111         // Check the initial state.
112         $this->check_current_state(question_state::$todo);
113         $this->check_current_mark(null);
114         $this->check_current_output(
115                 $this->get_contains_question_text_expectation($m),
116                 $this->get_does_not_contain_feedback_expectation());
117         $this->check_output_contains_selectoptions(
118                 $this->get_contains_select_expectation('sub0', $choices, null, true),
119                 $this->get_contains_select_expectation('sub1', $choices, null, true),
120                 $this->get_contains_select_expectation('sub2', $choices, null, true),
121                 $this->get_contains_select_expectation('sub3', $choices, null, true));
123         // Save a partial response.
124         $this->process_submission(array('sub0' => $orderforchoice[13],
125                 'sub1' => $orderforchoice[16], 'sub2' => '0', 'sub3' => '0'));
127         // Verify.
128         $this->check_current_state(question_state::$invalid);
129         $this->check_current_mark(null);
130         $this->check_current_output(
131                 $this->get_contains_question_text_expectation($m),
132                 $this->get_does_not_contain_feedback_expectation());
133         $this->check_output_contains_selectoptions(
134                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[13], true),
135                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[16], true),
136                 $this->get_contains_select_expectation('sub2', $choices, null, true),
137                 $this->get_contains_select_expectation('sub3', $choices, null, true));
139         // Finish the attempt.
140         $this->quba->finish_all_questions();
142         // Verify.
143         $this->check_current_state(question_state::$gradedpartial);
144         $this->check_current_mark(2);
145         $this->check_current_output(
146                 $this->get_contains_partcorrect_expectation());
147         $this->check_output_contains_selectoptions(
148                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[13], false),
149                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[16], false),
150                 $this->get_contains_select_expectation('sub2', $choices, null, false),
151                 $this->get_contains_select_expectation('sub3', $choices, null, false));
152     }
154     public function test_interactive_correct_no_submit() {
156         // Create a randomsamatching question.
157         $m = test_question_maker::make_question('randomsamatch');
158         $m->hints = array(
159             new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false),
160             new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true),
161         );
162         $m->shufflestems = false;
163         $this->start_attempt_at_question($m, 'interactive', 4);
165         $choiceorder = $m->get_choice_order();
166         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
167         $choices = [];
168         foreach ($choiceorder as $key => $choice) {
169             $choices[$key] = $m->choices[$choice];
170         }
172         // Check the initial state.
173         $this->check_current_state(question_state::$todo);
174         $this->check_current_mark(null);
175         $this->check_current_output(
176                 $this->get_contains_submit_button_expectation(true),
177                 $this->get_does_not_contain_feedback_expectation(),
178                 $this->get_tries_remaining_expectation(3),
179                 $this->get_no_hint_visible_expectation());
180         $this->check_output_contains_selectoptions(
181                 $this->get_contains_select_expectation('sub0', $choices, null, true),
182                 $this->get_contains_select_expectation('sub1', $choices, null, true),
183                 $this->get_contains_select_expectation('sub2', $choices, null, true),
184                 $this->get_contains_select_expectation('sub3', $choices, null, true));
186         // Save the right answer.
187         $this->process_submission(array('sub0' => $orderforchoice[13],
188                 'sub1' => $orderforchoice[16], 'sub2' => $orderforchoice[16],
189                 'sub3' => $orderforchoice[13]));
191         // Finish the attempt without clicking check.
192         $this->quba->finish_all_questions();
194         // Verify.
195         $this->check_current_state(question_state::$gradedright);
196         $this->check_current_mark(4);
197         $this->check_current_output(
198                 $this->get_does_not_contain_submit_button_expectation(),
199                 $this->get_contains_correct_expectation(),
200                 $this->get_no_hint_visible_expectation());
201         $this->check_output_contains_selectoptions(
202                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[13], false),
203                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[16], false),
204                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[16], false),
205                 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[13], false));
206     }
208     public function test_interactive_partial_no_submit() {
210         // Create a randomsamatching question.
211         $m = test_question_maker::make_question('randomsamatch');
212         $m->hints = array(
213             new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false),
214             new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true),
215         );
216         $m->shufflestems = false;
217         $this->start_attempt_at_question($m, 'interactive', 4);
219         $choiceorder = $m->get_choice_order();
220         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
221         $choices = [];
222         foreach ($choiceorder as $key => $choice) {
223             $choices[$key] = $m->choices[$choice];
224         }
226         // Check the initial state.
227         $this->check_current_state(question_state::$todo);
228         $this->check_current_mark(null);
229         $this->check_current_output(
230                 $this->get_contains_submit_button_expectation(true),
231                 $this->get_does_not_contain_feedback_expectation(),
232                 $this->get_tries_remaining_expectation(3),
233                 $this->get_no_hint_visible_expectation());
234         $this->check_output_contains_selectoptions(
235                 $this->get_contains_select_expectation('sub0', $choices, null, true),
236                 $this->get_contains_select_expectation('sub1', $choices, null, true),
237                 $this->get_contains_select_expectation('sub2', $choices, null, true),
238                 $this->get_contains_select_expectation('sub3', $choices, null, true));
240         // Save the right answer.
241         $this->process_submission(array('sub0' => $orderforchoice[13],
242                 'sub1' => $orderforchoice[16], 'sub2' => $orderforchoice[13],
243                 'sub3' => '0'));
245         // Finish the attempt without clicking check.
246         $this->quba->finish_all_questions();
248         // Verify.
249         $this->check_current_state(question_state::$gradedpartial);
250         $this->check_current_mark(2);
251         $this->check_current_output(
252                 $this->get_does_not_contain_submit_button_expectation(),
253                 $this->get_contains_partcorrect_expectation(),
254                 $this->get_no_hint_visible_expectation());
255         $this->check_output_contains_selectoptions(
256                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[13], false),
257                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[16], false),
258                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[13], false),
259                 $this->get_contains_select_expectation('sub3', $choices, null, false));
260     }
262     public function test_interactive_with_invalid() {
264         // Create a randomsamatching question.
265         $m = test_question_maker::make_question('randomsamatch');
266         $m->hints = array(
267             new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false),
268             new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true),
269         );
270         $m->shufflestems = false;
271         $this->start_attempt_at_question($m, 'interactive', 4);
273         $choiceorder = $m->get_choice_order();
274         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
275         $choices = [];
276         foreach ($choiceorder as $key => $choice) {
277             $choices[$key] = $m->choices[$choice];
278         }
280         // Check the initial state.
281         $this->check_current_state(question_state::$todo);
282         $this->check_current_mark(null);
283         $this->check_current_output(
284                 $this->get_contains_submit_button_expectation(true),
285                 $this->get_does_not_contain_feedback_expectation(),
286                 $this->get_tries_remaining_expectation(3),
287                 $this->get_no_hint_visible_expectation());
288         $this->check_output_contains_selectoptions(
289                 $this->get_contains_select_expectation('sub0', $choices, null, true),
290                 $this->get_contains_select_expectation('sub1', $choices, null, true),
291                 $this->get_contains_select_expectation('sub2', $choices, null, true),
292                 $this->get_contains_select_expectation('sub3', $choices, null, true));
294         // Try to submit an invalid answer.
295         $this->process_submission(array('sub0' => '0',
296                 'sub1' => '0', 'sub2' => '0',
297                 'sub3' => '0', '-submit' => '1'));
299         // Verify.
300         $this->check_current_state(question_state::$invalid);
301         $this->check_current_mark(null);
302         $this->check_current_output(
303                 $this->get_contains_submit_button_expectation(true),
304                 $this->get_does_not_contain_feedback_expectation(),
305                 $this->get_invalid_answer_expectation(),
306                 $this->get_no_hint_visible_expectation());
307         $this->check_output_contains_selectoptions(
308                 $this->get_contains_select_expectation('sub0', $choices, null, true),
309                 $this->get_contains_select_expectation('sub1', $choices, null, true),
310                 $this->get_contains_select_expectation('sub2', $choices, null, true),
311                 $this->get_contains_select_expectation('sub3', $choices, null, true));
313         // Now submit the right answer.
314         $this->process_submission(array('sub0' => $orderforchoice[13],
315                 'sub1' => $orderforchoice[16], 'sub2' => $orderforchoice[16],
316                 'sub3' => $orderforchoice[13], '-submit' => '1'));
318         // Verify.
319         $this->check_current_state(question_state::$gradedright);
320         $this->check_current_mark(4);
321         $this->check_current_output(
322                 $this->get_does_not_contain_submit_button_expectation(),
323                 $this->get_contains_correct_expectation(),
324                 $this->get_no_hint_visible_expectation());
325         $this->check_output_contains_selectoptions(
326                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[13], false),
327                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[16], false),
328                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[16], false),
329                 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[13], false));
330     }
332     public function test_randomsamatch_clear_wrong() {
334         // Create a randomsamatching question.
335         $m = test_question_maker::make_question('randomsamatch');
336         $m->hints = array(
337             new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, true),
338             new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true),
339         );
340         $m->shufflestems = false;
341         $this->start_attempt_at_question($m, 'interactive', 4);
343         $choiceorder = $m->get_choice_order();
344         $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder));
345         $choices = [];
346         foreach ($choiceorder as $key => $choice) {
347             $choices[$key] = $m->choices[$choice];
348         }
350         // Check the initial state.
351         $this->check_current_state(question_state::$todo);
352         $this->check_current_mark(null);
353         $this->check_current_output(
354                 $this->get_contains_submit_button_expectation(true),
355                 $this->get_does_not_contain_feedback_expectation(),
356                 $this->get_tries_remaining_expectation(3),
357                 $this->get_no_hint_visible_expectation());
358         $this->check_output_contains_selectoptions(
359                 $this->get_contains_select_expectation('sub0', $choices, null, true),
360                 $this->get_contains_select_expectation('sub1', $choices, null, true),
361                 $this->get_contains_select_expectation('sub2', $choices, null, true),
362                 $this->get_contains_select_expectation('sub3', $choices, null, true));
364         // Submit a completely wrong response.
365         $this->process_submission(array('sub0' => $orderforchoice[16],
366                 'sub1' => $orderforchoice[13], 'sub2' => $orderforchoice[13],
367                 'sub3' => $orderforchoice[16], '-submit' => 1));
369         // Verify.
370         $this->check_current_state(question_state::$todo);
371         $this->check_current_mark(null);
372         $this->check_current_output(
373                 $this->get_contains_hidden_expectation(
374                         $this->quba->get_field_prefix($this->slot) . 'sub0', '0'),
375                 $this->get_contains_hidden_expectation(
376                         $this->quba->get_field_prefix($this->slot) . 'sub1', '0'),
377                 $this->get_contains_hidden_expectation(
378                         $this->quba->get_field_prefix($this->slot) . 'sub2', '0'),
379                 $this->get_contains_hidden_expectation(
380                         $this->quba->get_field_prefix($this->slot) . 'sub3', '0'),
381                 $this->get_does_not_contain_submit_button_expectation(),
382                 $this->get_contains_hint_expectation('This is the first hint.'));
383         $this->check_output_contains_selectoptions(
384                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[16], false),
385                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[13], false),
386                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[13], false),
387                 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[16], false));
389         // Try again.
390         $this->process_submission(array('sub0' => 0,
391                 'sub1' => 0, 'sub2' => 0,
392                 'sub3' => 0, '-tryagain' => 1));
394         // Verify.
395         $this->check_current_state(question_state::$todo);
396         $this->check_current_mark(null);
397         $this->check_current_output(
398                 $this->get_contains_submit_button_expectation(true),
399                 $this->get_does_not_contain_feedback_expectation(),
400                 $this->get_tries_remaining_expectation(2),
401                 $this->get_no_hint_visible_expectation());
402         $this->check_output_contains_selectoptions(
403                 $this->get_contains_select_expectation('sub0', $choices, null, true),
404                 $this->get_contains_select_expectation('sub1', $choices, null, true),
405                 $this->get_contains_select_expectation('sub2', $choices, null, true),
406                 $this->get_contains_select_expectation('sub3', $choices, null, true));
408         // Submit a partially wrong response.
409         $this->process_submission(array('sub0' => $orderforchoice[16],
410                 'sub1' => $orderforchoice[13], 'sub2' => $orderforchoice[16],
411                 'sub3' => $orderforchoice[13], '-submit' => 1));
413         // Verify.
414         $this->check_current_state(question_state::$todo);
415         $this->check_current_mark(null);
416         $this->check_current_output(
417                 $this->get_contains_hidden_expectation(
418                         $this->quba->get_field_prefix($this->slot) . 'sub0', '0'),
419                 $this->get_contains_hidden_expectation(
420                         $this->quba->get_field_prefix($this->slot) . 'sub1', '0'),
421                 $this->get_contains_hidden_expectation(
422                         $this->quba->get_field_prefix($this->slot) . 'sub2', $orderforchoice[16]),
423                 $this->get_contains_hidden_expectation(
424                         $this->quba->get_field_prefix($this->slot) . 'sub3', $orderforchoice[13]),
425                 $this->get_does_not_contain_submit_button_expectation(),
426                 $this->get_contains_hint_expectation('This is the second hint.'));
427         $this->check_output_contains_selectoptions(
428                 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[16], false),
429                 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[13], false),
430                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[16], false),
431                 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[13], false));
433         // Try again.
434         $this->process_submission(array('sub0' => 0,
435                 'sub1' => 0, 'sub2' => $orderforchoice[16],
436                 'sub3' => $orderforchoice[13], '-tryagain' => 1));
438         // Verify.
439         $this->check_current_state(question_state::$todo);
440         $this->check_current_mark(null);
441         $this->check_current_output(
442                 $this->get_contains_submit_button_expectation(true),
443                 $this->get_does_not_contain_feedback_expectation(),
444                 $this->get_tries_remaining_expectation(1),
445                 $this->get_no_hint_visible_expectation());
446         $this->check_output_contains_selectoptions(
447                 $this->get_contains_select_expectation('sub0', $choices, null, true),
448                 $this->get_contains_select_expectation('sub1', $choices, null, true),
449                 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[16], true),
450                 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[13], true));
451     }