Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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_randomsamatch
  22   * @copyright 2013 Jean-Michel Vedrine
  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 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 {
  40  
  41      public function test_deferred_feedback_unanswered() {
  42  
  43          // Create a randomsamatch question.
  44          $m = test_question_maker::make_question('randomsamatch');
  45          $this->start_attempt_at_question($m, 'deferredfeedback', 4);
  46  
  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          }
  53  
  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);
  66  
  67          // Save a blank response.
  68          $this->process_submission(array('sub0' => '0', 'sub1' => '0',
  69                  'sub2' => '0', 'sub3' => '0'));
  70  
  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);
  83  
  84          // Finish the attempt.
  85          $this->quba->finish_all_questions();
  86  
  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      }
  96  
  97      public function test_deferred_feedback_partial_answer() {
  98  
  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);
 103  
 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          }
 110  
 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));
 122  
 123          // Save a partial response.
 124          $this->process_submission(array('sub0' => $orderforchoice[13],
 125                  'sub1' => $orderforchoice[16], 'sub2' => '0', 'sub3' => '0'));
 126  
 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));
 138  
 139          // Finish the attempt.
 140          $this->quba->finish_all_questions();
 141  
 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      }
 153  
 154      public function test_interactive_correct_no_submit() {
 155  
 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);
 164  
 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          }
 171  
 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));
 185  
 186          // Save the right answer.
 187          $this->process_submission(array('sub0' => $orderforchoice[13],
 188                  'sub1' => $orderforchoice[16], 'sub2' => $orderforchoice[16],
 189                  'sub3' => $orderforchoice[13]));
 190  
 191          // Finish the attempt without clicking check.
 192          $this->quba->finish_all_questions();
 193  
 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      }
 207  
 208      public function test_interactive_partial_no_submit() {
 209  
 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);
 218  
 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          }
 225  
 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));
 239  
 240          // Save the right answer.
 241          $this->process_submission(array('sub0' => $orderforchoice[13],
 242                  'sub1' => $orderforchoice[16], 'sub2' => $orderforchoice[13],
 243                  'sub3' => '0'));
 244  
 245          // Finish the attempt without clicking check.
 246          $this->quba->finish_all_questions();
 247  
 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      }
 261  
 262      public function test_interactive_with_invalid() {
 263  
 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);
 272  
 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          }
 279  
 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));
 293  
 294          // Try to submit an invalid answer.
 295          $this->process_submission(array('sub0' => '0',
 296                  'sub1' => '0', 'sub2' => '0',
 297                  'sub3' => '0', '-submit' => '1'));
 298  
 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));
 312  
 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'));
 317  
 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      }
 331  
 332      public function test_randomsamatch_clear_wrong() {
 333  
 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);
 342  
 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          }
 349  
 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));
 363  
 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));
 368  
 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));
 388  
 389          // Try again.
 390          $this->process_submission(array('sub0' => 0,
 391                  'sub1' => 0, 'sub2' => 0,
 392                  'sub3' => 0, '-tryagain' => 1));
 393  
 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));
 407  
 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));
 412  
 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));
 432  
 433          // Try again.
 434          $this->process_submission(array('sub0' => 0,
 435                  'sub1' => 0, 'sub2' => $orderforchoice[16],
 436                  'sub3' => $orderforchoice[13], '-tryagain' => 1));
 437  
 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      }
 452  }