See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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 a question through the interactive 19 * behaviour. 20 * 21 * @package qtype_match 22 * @copyright 2010 The Open University 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 global $CFG; 30 require_once($CFG->dirroot . '/question/engine/tests/helpers.php'); 31 32 33 /** 34 * Unit tests for the matching 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_match_walkthrough_test extends qbehaviour_walkthrough_test_base { 40 41 public function test_deferred_feedback_unanswered() { 42 43 // Create a matching question. 44 $m = test_question_maker::make_question('match'); 45 $m->shufflestems = false; 46 $this->start_attempt_at_question($m, 'deferredfeedback', 4); 47 48 $choiceorder = $m->get_choice_order(); 49 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 50 $choices = array(0 => get_string('choose') . '...'); 51 foreach ($choiceorder as $key => $choice) { 52 $choices[$key] = $m->choices[$choice]; 53 } 54 55 // Check the initial state. 56 $this->check_current_state(question_state::$todo); 57 $this->check_current_mark(null); 58 $this->check_current_output( 59 $this->get_contains_question_text_expectation($m), 60 $this->get_does_not_contain_feedback_expectation()); 61 $this->check_output_contains_selectoptions( 62 $this->get_contains_select_expectation('sub0', $choices, null, true), 63 $this->get_contains_select_expectation('sub1', $choices, null, true), 64 $this->get_contains_select_expectation('sub2', $choices, null, true), 65 $this->get_contains_select_expectation('sub3', $choices, null, true)); 66 $this->check_step_count(1); 67 68 // Save a blank response. 69 $this->process_submission(array('sub0' => '0', 'sub1' => '0', 70 'sub2' => '0', 'sub3' => '0')); 71 72 // Verify. 73 $this->check_current_state(question_state::$todo); 74 $this->check_current_mark(null); 75 $this->check_current_output( 76 $this->get_contains_question_text_expectation($m), 77 $this->get_does_not_contain_feedback_expectation()); 78 $this->check_output_contains_selectoptions( 79 $this->get_contains_select_expectation('sub0', $choices, null, true), 80 $this->get_contains_select_expectation('sub1', $choices, null, true), 81 $this->get_contains_select_expectation('sub2', $choices, null, true), 82 $this->get_contains_select_expectation('sub3', $choices, null, true)); 83 $this->check_step_count(1); 84 85 // Finish the attempt. 86 $this->quba->finish_all_questions(); 87 88 // Verify. 89 $this->check_current_state(question_state::$gaveup); 90 $this->check_current_mark(null); 91 $this->check_output_contains_selectoptions( 92 $this->get_contains_select_expectation('sub0', $choices, null, false), 93 $this->get_contains_select_expectation('sub1', $choices, null, false), 94 $this->get_contains_select_expectation('sub2', $choices, null, false), 95 $this->get_contains_select_expectation('sub3', $choices, null, false)); 96 } 97 98 public function test_deferred_feedback_partial_answer() { 99 100 // Create a matching question. 101 $m = test_question_maker::make_question('match'); 102 $m->shufflestems = false; 103 $this->start_attempt_at_question($m, 'deferredfeedback', 4); 104 105 $choiceorder = $m->get_choice_order(); 106 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 107 $choices = array(0 => get_string('choose') . '...'); 108 foreach ($choiceorder as $key => $choice) { 109 $choices[$key] = $m->choices[$choice]; 110 } 111 112 // Check the initial state. 113 $this->check_current_state(question_state::$todo); 114 $this->check_current_mark(null); 115 $this->check_current_output( 116 $this->get_contains_question_text_expectation($m), 117 $this->get_does_not_contain_feedback_expectation()); 118 $this->check_output_contains_selectoptions( 119 $this->get_contains_select_expectation('sub0', $choices, null, true), 120 $this->get_contains_select_expectation('sub1', $choices, null, true), 121 $this->get_contains_select_expectation('sub2', $choices, null, true), 122 $this->get_contains_select_expectation('sub3', $choices, null, true)); 123 124 // Save a partial response. 125 $this->process_submission(array('sub0' => $orderforchoice[1], 126 'sub1' => $orderforchoice[2], 'sub2' => '0', 'sub3' => '0')); 127 128 // Verify. 129 $this->check_current_state(question_state::$invalid); 130 $this->check_current_mark(null); 131 $this->check_current_output( 132 $this->get_contains_question_text_expectation($m), 133 $this->get_does_not_contain_feedback_expectation()); 134 $this->check_output_contains_selectoptions( 135 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[1], true), 136 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[2], true), 137 $this->get_contains_select_expectation('sub2', $choices, null, true), 138 $this->get_contains_select_expectation('sub3', $choices, null, true)); 139 140 // Finish the attempt. 141 $this->quba->finish_all_questions(); 142 143 // Verify. 144 $this->check_current_state(question_state::$gradedpartial); 145 $this->check_current_mark(2); 146 $this->check_current_output( 147 $this->get_contains_partcorrect_expectation()); 148 $this->check_output_contains_selectoptions( 149 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[1], false), 150 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[2], false), 151 $this->get_contains_select_expectation('sub2', $choices, null, false), 152 $this->get_contains_select_expectation('sub3', $choices, null, false)); 153 } 154 155 public function test_interactive_correct_no_submit() { 156 157 // Create a matching question. 158 $m = test_question_maker::make_question('match'); 159 $m->hints = array( 160 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false), 161 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 162 ); 163 $m->shufflestems = false; 164 $this->start_attempt_at_question($m, 'interactive', 4); 165 166 $choiceorder = $m->get_choice_order(); 167 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 168 $choices = array(0 => get_string('choose') . '...'); 169 foreach ($choiceorder as $key => $choice) { 170 $choices[$key] = $m->choices[$choice]; 171 } 172 173 // Check the initial state. 174 $this->check_current_state(question_state::$todo); 175 $this->check_current_mark(null); 176 $this->check_current_output( 177 $this->get_contains_submit_button_expectation(true), 178 $this->get_does_not_contain_feedback_expectation(), 179 $this->get_tries_remaining_expectation(3), 180 $this->get_no_hint_visible_expectation()); 181 $this->check_output_contains_selectoptions( 182 $this->get_contains_select_expectation('sub0', $choices, null, true), 183 $this->get_contains_select_expectation('sub1', $choices, null, true), 184 $this->get_contains_select_expectation('sub2', $choices, null, true), 185 $this->get_contains_select_expectation('sub3', $choices, null, true)); 186 187 // Save the right answer. 188 $this->process_submission(array('sub0' => $orderforchoice[1], 189 'sub1' => $orderforchoice[2], 'sub2' => $orderforchoice[2], 190 'sub3' => $orderforchoice[1])); 191 192 // Finish the attempt without clicking check. 193 $this->quba->finish_all_questions(); 194 195 // Verify. 196 $this->check_current_state(question_state::$gradedright); 197 $this->check_current_mark(4); 198 $this->check_current_output( 199 $this->get_does_not_contain_submit_button_expectation(), 200 $this->get_contains_correct_expectation(), 201 $this->get_no_hint_visible_expectation()); 202 $this->check_output_contains_selectoptions( 203 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[1], false), 204 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[2], false), 205 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[2], false), 206 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[1], false)); 207 } 208 209 public function test_interactive_partial_no_submit() { 210 211 // Create a matching question. 212 $m = test_question_maker::make_question('match'); 213 $m->hints = array( 214 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false), 215 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 216 ); 217 $m->shufflestems = false; 218 $this->start_attempt_at_question($m, 'interactive', 4); 219 220 $choiceorder = $m->get_choice_order(); 221 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 222 $choices = array(0 => get_string('choose') . '...'); 223 foreach ($choiceorder as $key => $choice) { 224 $choices[$key] = $m->choices[$choice]; 225 } 226 227 // Check the initial state. 228 $this->check_current_state(question_state::$todo); 229 $this->check_current_mark(null); 230 $this->check_current_output( 231 $this->get_contains_submit_button_expectation(true), 232 $this->get_does_not_contain_feedback_expectation(), 233 $this->get_tries_remaining_expectation(3), 234 $this->get_no_hint_visible_expectation()); 235 $this->check_output_contains_selectoptions( 236 $this->get_contains_select_expectation('sub0', $choices, null, true), 237 $this->get_contains_select_expectation('sub1', $choices, null, true), 238 $this->get_contains_select_expectation('sub2', $choices, null, true), 239 $this->get_contains_select_expectation('sub3', $choices, null, true)); 240 241 // Save the right answer. 242 $this->process_submission(array('sub0' => $orderforchoice[1], 243 'sub1' => $orderforchoice[2], 'sub2' => $orderforchoice[1], 244 'sub3' => '0')); 245 246 // Finish the attempt without clicking check. 247 $this->quba->finish_all_questions(); 248 249 // Verify. 250 $this->check_current_state(question_state::$gradedpartial); 251 $this->check_current_mark(2); 252 $this->check_current_output( 253 $this->get_does_not_contain_submit_button_expectation(), 254 $this->get_contains_partcorrect_expectation(), 255 $this->get_no_hint_visible_expectation()); 256 $this->check_output_contains_selectoptions( 257 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[1], false), 258 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[2], false), 259 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[1], false), 260 $this->get_contains_select_expectation('sub3', $choices, null, false)); 261 } 262 263 public function test_interactive_with_invalid() { 264 265 // Create a matching question. 266 $m = test_question_maker::make_question('match'); 267 $m->hints = array( 268 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, false), 269 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 270 ); 271 $m->shufflestems = false; 272 $this->start_attempt_at_question($m, 'interactive', 4); 273 274 $choiceorder = $m->get_choice_order(); 275 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 276 $choices = array(0 => get_string('choose') . '...'); 277 foreach ($choiceorder as $key => $choice) { 278 $choices[$key] = $m->choices[$choice]; 279 } 280 281 // Check the initial state. 282 $this->check_current_state(question_state::$todo); 283 $this->check_current_mark(null); 284 $this->check_current_output( 285 $this->get_contains_submit_button_expectation(true), 286 $this->get_does_not_contain_feedback_expectation(), 287 $this->get_tries_remaining_expectation(3), 288 $this->get_no_hint_visible_expectation()); 289 $this->check_output_contains_selectoptions( 290 $this->get_contains_select_expectation('sub0', $choices, null, true), 291 $this->get_contains_select_expectation('sub1', $choices, null, true), 292 $this->get_contains_select_expectation('sub2', $choices, null, true), 293 $this->get_contains_select_expectation('sub3', $choices, null, true)); 294 295 // Try to submit an invalid answer. 296 $this->process_submission(array('sub0' => '0', 297 'sub1' => '0', 'sub2' => '0', 298 'sub3' => '0', '-submit' => '1')); 299 300 // Verify. 301 $this->check_current_state(question_state::$invalid); 302 $this->check_current_mark(null); 303 $this->check_current_output( 304 $this->get_contains_submit_button_expectation(true), 305 $this->get_does_not_contain_feedback_expectation(), 306 $this->get_invalid_answer_expectation(), 307 $this->get_no_hint_visible_expectation()); 308 $this->check_output_contains_selectoptions( 309 $this->get_contains_select_expectation('sub0', $choices, null, true), 310 $this->get_contains_select_expectation('sub1', $choices, null, true), 311 $this->get_contains_select_expectation('sub2', $choices, null, true), 312 $this->get_contains_select_expectation('sub3', $choices, null, true)); 313 314 // Now submit the right answer. 315 $this->process_submission(array('sub0' => $orderforchoice[1], 316 'sub1' => $orderforchoice[2], 'sub2' => $orderforchoice[2], 317 'sub3' => $orderforchoice[1], '-submit' => '1')); 318 319 // Verify. 320 $this->check_current_state(question_state::$gradedright); 321 $this->check_current_mark(4); 322 $this->check_current_output( 323 $this->get_does_not_contain_submit_button_expectation(), 324 $this->get_contains_correct_expectation(), 325 $this->get_no_hint_visible_expectation()); 326 $this->check_output_contains_selectoptions( 327 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[1], false), 328 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[2], false), 329 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[2], false), 330 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[1], false)); 331 } 332 333 public function test_match_with_tricky_html_choices() { 334 335 // Create a matching question. 336 $m = test_question_maker::make_question('match'); 337 $m->stems = array( 338 1 => '(1, 2]', 339 2 => '[1, 2]', 340 3 => '[1, 2)', 341 ); 342 $m->choices = array( 343 1 => '1 < x ≤ 2', 344 2 => '1 ≤ x ≤ 2', 345 3 => '1 ≤ x < 2', 346 ); 347 $m->right = array(1 => 1, 2 => 2, 3 => 3); 348 $m->shufflestems = false; 349 $this->start_attempt_at_question($m, 'deferredfeedback', 3); 350 351 $choiceorder = $m->get_choice_order(); 352 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 353 $choices = array(0 => get_string('choose') . '...'); 354 foreach ($choiceorder as $key => $choice) { 355 $choices[$key] = $m->choices[$choice]; 356 } 357 358 // Check the initial state. 359 $this->check_current_state(question_state::$todo); 360 $this->check_current_mark(null); 361 // Do not use check_output_contains_selectoptions as there are multibyte characters ('1 ≤ x ≤ 2') that 362 // seem to be read as ascii ('1 ≤ x ≤ 2') in this test. 363 $this->check_current_output( 364 $this->get_contains_select_expectation('sub0', $choices, null, true), 365 $this->get_contains_select_expectation('sub1', $choices, null, true), 366 $this->get_contains_select_expectation('sub2', $choices, null, true), 367 $this->get_contains_question_text_expectation($m), 368 $this->get_does_not_contain_feedback_expectation()); 369 $this->check_step_count(1); 370 371 $rightresponse = array('sub0' => $orderforchoice[1], 372 'sub1' => $orderforchoice[2], 'sub2' => $orderforchoice[3]); 373 $rightresponsesummary = 374 '(1, 2] -> 1 < x ≤ 2; [1, 2] -> 1 ≤ x ≤ 2; [1, 2) -> 1 ≤ x < 2'; 375 376 $this->process_submission($rightresponse); 377 $this->finish(); 378 379 $this->assertEquals($rightresponsesummary, $m->summarise_response($rightresponse)); 380 381 $this->displayoptions->history = 1; 382 $this->check_current_output( 383 new question_pattern_expectation('/' . 384 preg_quote(htmlspecialchars($rightresponsesummary), '/') . '/')); 385 } 386 387 public function test_match_clear_wrong() { 388 389 // Create a matching question. 390 $m = test_question_maker::make_question('match'); 391 $m->hints = array( 392 new question_hint_with_parts(11, 'This is the first hint.', FORMAT_HTML, false, true), 393 new question_hint_with_parts(12, 'This is the second hint.', FORMAT_HTML, true, true), 394 ); 395 $m->shufflestems = false; 396 $this->start_attempt_at_question($m, 'interactive', 4); 397 398 $choiceorder = $m->get_choice_order(); 399 $orderforchoice = array_combine(array_values($choiceorder), array_keys($choiceorder)); 400 $choices = array(0 => get_string('choose') . '...'); 401 foreach ($choiceorder as $key => $choice) { 402 $choices[$key] = $m->choices[$choice]; 403 } 404 405 // Check the initial state. 406 $this->check_current_state(question_state::$todo); 407 $this->check_current_mark(null); 408 $this->check_current_output( 409 $this->get_contains_submit_button_expectation(true), 410 $this->get_does_not_contain_feedback_expectation(), 411 $this->get_tries_remaining_expectation(3), 412 $this->get_no_hint_visible_expectation()); 413 $this->check_output_contains_selectoptions( 414 $this->get_contains_select_expectation('sub0', $choices, null, true), 415 $this->get_contains_select_expectation('sub1', $choices, null, true), 416 $this->get_contains_select_expectation('sub2', $choices, null, true), 417 $this->get_contains_select_expectation('sub3', $choices, null, true)); 418 419 // Submit a completely wrong response. 420 $this->process_submission(array('sub0' => $orderforchoice[3], 421 'sub1' => $orderforchoice[3], 'sub2' => $orderforchoice[3], 422 'sub3' => $orderforchoice[3], '-submit' => 1)); 423 424 // Verify. 425 $this->check_current_state(question_state::$todo); 426 $this->check_current_mark(null); 427 $this->check_current_output( 428 $this->get_contains_hidden_expectation( 429 $this->quba->get_field_prefix($this->slot) . 'sub0', '0'), 430 $this->get_contains_hidden_expectation( 431 $this->quba->get_field_prefix($this->slot) . 'sub1', '0'), 432 $this->get_contains_hidden_expectation( 433 $this->quba->get_field_prefix($this->slot) . 'sub2', '0'), 434 $this->get_contains_hidden_expectation( 435 $this->quba->get_field_prefix($this->slot) . 'sub3', '0'), 436 $this->get_does_not_contain_submit_button_expectation(), 437 $this->get_contains_hint_expectation('This is the first hint.')); 438 $this->check_output_contains_selectoptions( 439 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[3], false), 440 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[3], false), 441 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[3], false), 442 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[3], false)); 443 444 // Try again. 445 $this->process_submission(array('sub0' => 0, 446 'sub1' => 0, 'sub2' => 0, 447 'sub3' => 0, '-tryagain' => 1)); 448 449 // Verify. 450 $this->check_current_state(question_state::$todo); 451 $this->check_current_mark(null); 452 $this->check_current_output( 453 $this->get_contains_submit_button_expectation(true), 454 $this->get_does_not_contain_feedback_expectation(), 455 $this->get_tries_remaining_expectation(2), 456 $this->get_no_hint_visible_expectation()); 457 $this->check_output_contains_selectoptions( 458 $this->get_contains_select_expectation('sub0', $choices, null, true), 459 $this->get_contains_select_expectation('sub1', $choices, null, true), 460 $this->get_contains_select_expectation('sub2', $choices, null, true), 461 $this->get_contains_select_expectation('sub3', $choices, null, true)); 462 463 // Submit a partially wrong response. 464 $this->process_submission(array('sub0' => $orderforchoice[3], 465 'sub1' => $orderforchoice[3], 'sub2' => $orderforchoice[2], 466 'sub3' => $orderforchoice[1], '-submit' => 1)); 467 468 // Verify. 469 $this->check_current_state(question_state::$todo); 470 $this->check_current_mark(null); 471 $this->check_current_output( 472 $this->get_contains_hidden_expectation( 473 $this->quba->get_field_prefix($this->slot) . 'sub0', '0'), 474 $this->get_contains_hidden_expectation( 475 $this->quba->get_field_prefix($this->slot) . 'sub1', '0'), 476 $this->get_contains_hidden_expectation( 477 $this->quba->get_field_prefix($this->slot) . 'sub2', $orderforchoice[2]), 478 $this->get_contains_hidden_expectation( 479 $this->quba->get_field_prefix($this->slot) . 'sub3', $orderforchoice[1]), 480 $this->get_does_not_contain_submit_button_expectation(), 481 $this->get_contains_hint_expectation('This is the second hint.')); 482 $this->check_output_contains_selectoptions( 483 $this->get_contains_select_expectation('sub0', $choices, $orderforchoice[3], false), 484 $this->get_contains_select_expectation('sub1', $choices, $orderforchoice[3], false), 485 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[2], false), 486 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[1], false)); 487 488 // Try again. 489 $this->process_submission(array('sub0' => 0, 490 'sub1' => 0, 'sub2' => $orderforchoice[2], 491 'sub3' => $orderforchoice[1], '-tryagain' => 1)); 492 493 // Verify. 494 $this->check_current_state(question_state::$todo); 495 $this->check_current_mark(null); 496 $this->check_current_output( 497 $this->get_contains_submit_button_expectation(true), 498 $this->get_does_not_contain_feedback_expectation(), 499 $this->get_tries_remaining_expectation(1), 500 $this->get_no_hint_visible_expectation()); 501 $this->check_output_contains_selectoptions( 502 $this->get_contains_select_expectation('sub0', $choices, null, true), 503 $this->get_contains_select_expectation('sub1', $choices, null, true), 504 $this->get_contains_select_expectation('sub2', $choices, $orderforchoice[2], true), 505 $this->get_contains_select_expectation('sub3', $choices, $orderforchoice[1], true)); 506 507 } 508 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body