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   * Unit tests for the drag-and-drop words into sentences question type.
  19   *
  20   * @package   qtype_ddwtos
  21   * @copyright 2012 The Open University
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  global $CFG;
  28  
  29  require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  30  require_once($CFG->dirroot . '/question/type/ddwtos/tests/helper.php');
  31  
  32  
  33  /**
  34   * Unit tests for the drag-and-drop words into sentences question type.
  35   *
  36   * @copyright 2012 The Open University
  37   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class qtype_ddwtos_walkthrough_test extends qbehaviour_walkthrough_test_base {
  40  
  41      protected function get_contains_drop_box_expectation($place, $group, $readonly,
  42              $stateclass = '0') {
  43          $qa = $this->quba->get_question_attempt($this->slot);
  44  
  45          $class = "place{$place} drop group{$group}";
  46          if ($readonly) {
  47              $class .= ' readonly';
  48          } else {
  49              $expectedattrs['tabindex'] = 0;
  50          }
  51          $expectedattrs['class'] = $class;
  52  
  53          return new question_contains_tag_with_attributes('span', $expectedattrs);
  54      }
  55  
  56      public function test_interactive_behaviour() {
  57  
  58          // Create a drag-and-drop question.
  59          $dd = test_question_maker::make_question('ddwtos');
  60          $dd->hints = array(
  61              new question_hint_with_parts(13, 'This is the first hint.', FORMAT_HTML, false, false),
  62              new question_hint_with_parts(14, 'This is the second hint.', FORMAT_HTML, true, true),
  63          );
  64          $dd->shufflechoices = false;
  65          $this->start_attempt_at_question($dd, 'interactive', 3);
  66  
  67          // Check the initial state.
  68          $this->check_current_state(question_state::$todo);
  69          $this->check_current_mark(null);
  70          $this->check_current_output(
  71                  $this->get_contains_drop_box_expectation('1', 1, false),
  72                  $this->get_contains_drop_box_expectation('2', 2, false),
  73                  $this->get_contains_drop_box_expectation('3', 3, false),
  74                  $this->get_contains_hidden_expectation(
  75                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
  76                  $this->get_contains_hidden_expectation(
  77                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
  78                  $this->get_contains_hidden_expectation(
  79                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
  80                  $this->get_contains_submit_button_expectation(true),
  81                  $this->get_does_not_contain_feedback_expectation(),
  82                  $this->get_tries_remaining_expectation(3),
  83                  $this->get_no_hint_visible_expectation());
  84  
  85          // Save the wrong answer.
  86          $this->process_submission(array('p1' => '2', 'p2' => '2', 'p3' => '2'));
  87  
  88          // Verify.
  89          $this->check_current_state(question_state::$todo);
  90          $this->check_current_mark(null);
  91          $this->check_current_output(
  92                  $this->get_contains_drop_box_expectation('1', 1, false),
  93                  $this->get_contains_drop_box_expectation('2', 2, false),
  94                  $this->get_contains_drop_box_expectation('3', 3, false),
  95                  $this->get_contains_hidden_expectation(
  96                          $this->quba->get_field_prefix($this->slot) . 'p1', '2'),
  97                  $this->get_contains_hidden_expectation(
  98                          $this->quba->get_field_prefix($this->slot) . 'p2', '2'),
  99                  $this->get_contains_hidden_expectation(
 100                          $this->quba->get_field_prefix($this->slot) . 'p3', '2'),
 101                  $this->get_contains_submit_button_expectation(true),
 102                  $this->get_does_not_contain_correctness_expectation(),
 103                  $this->get_does_not_contain_feedback_expectation(),
 104                  $this->get_tries_remaining_expectation(3),
 105                  $this->get_no_hint_visible_expectation());
 106  
 107          // Submit the wrong answer.
 108          $this->process_submission(array('p1' => '2', 'p2' => '2', 'p3' => '2', '-submit' => 1));
 109  
 110          // Verify.
 111          $this->check_current_state(question_state::$todo);
 112          $this->check_current_mark(null);
 113          $this->check_current_output(
 114                  $this->get_contains_drop_box_expectation('1', 1, true),
 115                  $this->get_contains_drop_box_expectation('2', 2, true),
 116                  $this->get_contains_drop_box_expectation('3', 3, true),
 117                  $this->get_does_not_contain_submit_button_expectation(),
 118                  $this->get_contains_try_again_button_expectation(true),
 119                  $this->get_does_not_contain_correctness_expectation(),
 120                  $this->get_contains_hint_expectation('This is the first hint'));
 121  
 122          // Do try again.
 123          $this->process_submission(array('-tryagain' => 1));
 124  
 125          // Verify.
 126          $this->check_current_state(question_state::$todo);
 127          $this->check_current_mark(null);
 128          $this->check_current_output(
 129                  $this->get_contains_drop_box_expectation('1', 1, false),
 130                  $this->get_contains_drop_box_expectation('2', 2, false),
 131                  $this->get_contains_drop_box_expectation('3', 3, false),
 132                  $this->get_contains_hidden_expectation(
 133                          $this->quba->get_field_prefix($this->slot) . 'p1', '2'),
 134                  $this->get_contains_hidden_expectation(
 135                          $this->quba->get_field_prefix($this->slot) . 'p2', '2'),
 136                  $this->get_contains_hidden_expectation(
 137                          $this->quba->get_field_prefix($this->slot) . 'p3', '2'),
 138                  $this->get_contains_submit_button_expectation(true),
 139                  $this->get_does_not_contain_correctness_expectation(),
 140                  $this->get_does_not_contain_feedback_expectation(),
 141                  $this->get_tries_remaining_expectation(2),
 142                  $this->get_no_hint_visible_expectation());
 143  
 144          // Submit the right answer.
 145          $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '1', '-submit' => 1));
 146  
 147          // Verify.
 148          $this->check_current_state(question_state::$gradedright);
 149          $this->check_current_mark(2);
 150          $this->check_current_output(
 151                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 152                  $this->get_contains_drop_box_expectation('2', 2, true, 'correct'),
 153                  $this->get_contains_drop_box_expectation('3', 3, true, 'correct'),
 154                  $this->get_does_not_contain_submit_button_expectation(),
 155                  $this->get_contains_correct_expectation(),
 156                  $this->get_no_hint_visible_expectation());
 157  
 158          // Check regrading does not mess anything up.
 159          $this->quba->regrade_all_questions();
 160  
 161          // Verify.
 162          $this->check_current_state(question_state::$gradedright);
 163          $this->check_current_mark(2);
 164      }
 165  
 166      public function test_deferred_feedback() {
 167  
 168          // Create a drag-and-drop question.
 169          $dd = test_question_maker::make_question('ddwtos');
 170          $dd->shufflechoices = false;
 171          $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
 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_drop_box_expectation('1', 1, false),
 178                  $this->get_contains_drop_box_expectation('2', 2, false),
 179                  $this->get_contains_drop_box_expectation('3', 3, false),
 180                  $this->get_contains_hidden_expectation(
 181                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 182                  $this->get_contains_hidden_expectation(
 183                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 184                  $this->get_contains_hidden_expectation(
 185                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 186                  $this->get_does_not_contain_feedback_expectation());
 187  
 188          // Save a partial answer.
 189          $this->process_submission(array('p1' => '1', 'p2' => '2'));
 190  
 191          // Verify.
 192          $this->check_current_state(question_state::$invalid);
 193          $this->check_current_mark(null);
 194          $this->check_current_output(
 195                  $this->get_contains_drop_box_expectation('1', 1, false),
 196                  $this->get_contains_drop_box_expectation('2', 2, false),
 197                  $this->get_contains_drop_box_expectation('3', 3, false),
 198                  $this->get_contains_hidden_expectation(
 199                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 200                  $this->get_contains_hidden_expectation(
 201                          $this->quba->get_field_prefix($this->slot) . 'p2', '2'),
 202                  $this->get_contains_hidden_expectation(
 203                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 204                  $this->get_does_not_contain_correctness_expectation(),
 205                  $this->get_does_not_contain_feedback_expectation());
 206  
 207          // Save the right answer.
 208          $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '1'));
 209  
 210          // Verify.
 211          $this->check_current_state(question_state::$complete);
 212          $this->check_current_mark(null);
 213          $this->check_current_output(
 214                  $this->get_contains_drop_box_expectation('1', 1, false),
 215                  $this->get_contains_drop_box_expectation('2', 2, false),
 216                  $this->get_contains_drop_box_expectation('3', 3, false),
 217                  $this->get_contains_hidden_expectation(
 218                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 219                  $this->get_contains_hidden_expectation(
 220                          $this->quba->get_field_prefix($this->slot) . 'p2', '1'),
 221                  $this->get_contains_hidden_expectation(
 222                          $this->quba->get_field_prefix($this->slot) . 'p3', '1'),
 223                  $this->get_does_not_contain_correctness_expectation(),
 224                  $this->get_does_not_contain_feedback_expectation());
 225  
 226          // Finish the attempt.
 227          $this->quba->finish_all_questions();
 228  
 229          // Verify.
 230          $this->check_current_state(question_state::$gradedright);
 231          $this->check_current_mark(3);
 232          $this->check_current_output(
 233                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 234                  $this->get_contains_drop_box_expectation('2', 2, true, 'correct'),
 235                  $this->get_contains_drop_box_expectation('3', 3, true, 'correct'),
 236                  $this->get_contains_correct_expectation());
 237  
 238          // Change the right answer a bit.
 239          $dd->rightchoices[2] = 2;
 240  
 241          // Check regrading does not mess anything up.
 242          $this->quba->regrade_all_questions();
 243  
 244          // Verify.
 245          $this->check_current_state(question_state::$gradedpartial);
 246          $this->check_current_mark(2);
 247      }
 248  
 249      public function test_deferred_feedback_unanswered() {
 250  
 251          // Create a drag-and-drop question.
 252          $dd = test_question_maker::make_question('ddwtos');
 253          $dd->shufflechoices = false;
 254          $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
 255  
 256          // Check the initial state.
 257          $this->check_current_state(question_state::$todo);
 258          $this->check_current_mark(null);
 259          $this->check_current_output(
 260                  $this->get_contains_drop_box_expectation('1', 1, false),
 261                  $this->get_contains_drop_box_expectation('2', 2, false),
 262                  $this->get_contains_drop_box_expectation('3', 3, false),
 263                  $this->get_contains_hidden_expectation(
 264                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 265                  $this->get_contains_hidden_expectation(
 266                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 267                  $this->get_contains_hidden_expectation(
 268                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 269                  $this->get_does_not_contain_correctness_expectation(),
 270                  $this->get_does_not_contain_feedback_expectation());
 271          $this->check_step_count(1);
 272  
 273          // Save a blank response.
 274          $this->process_submission(array('p1' => '0', 'p2' => '0', 'p3' => '0'));
 275  
 276          // Verify.
 277          $this->check_current_state(question_state::$todo);
 278          $this->check_current_mark(null);
 279          $this->check_current_output(
 280                  $this->get_contains_drop_box_expectation('1', 1, false),
 281                  $this->get_contains_drop_box_expectation('2', 2, false),
 282                  $this->get_contains_drop_box_expectation('3', 3, false),
 283                  $this->get_contains_hidden_expectation(
 284                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 285                  $this->get_contains_hidden_expectation(
 286                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 287                  $this->get_contains_hidden_expectation(
 288                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 289                  $this->get_does_not_contain_correctness_expectation(),
 290                  $this->get_does_not_contain_feedback_expectation());
 291          $this->check_step_count(1);
 292  
 293          // Finish the attempt.
 294          $this->quba->finish_all_questions();
 295  
 296          // Verify.
 297          $this->check_current_state(question_state::$gaveup);
 298          $this->check_current_mark(null);
 299          $this->check_current_output(
 300                  $this->get_contains_drop_box_expectation('1', 1, true),
 301                  $this->get_contains_drop_box_expectation('2', 2, true),
 302                  $this->get_contains_drop_box_expectation('3', 3, true));
 303      }
 304  
 305      public function test_deferred_feedback_partial_answer() {
 306  
 307          // Create a drag-and-drop question.
 308          $dd = test_question_maker::make_question('ddwtos');
 309          $dd->shufflechoices = false;
 310          $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
 311  
 312          // Check the initial state.
 313          $this->check_current_state(question_state::$todo);
 314          $this->check_current_mark(null);
 315          $this->check_current_output(
 316                  $this->get_contains_drop_box_expectation('1', 1, false),
 317                  $this->get_contains_drop_box_expectation('2', 2, false),
 318                  $this->get_contains_drop_box_expectation('3', 3, false),
 319                  $this->get_contains_hidden_expectation(
 320                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 321                  $this->get_contains_hidden_expectation(
 322                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 323                  $this->get_contains_hidden_expectation(
 324                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 325                  $this->get_does_not_contain_correctness_expectation(),
 326                  $this->get_does_not_contain_feedback_expectation());
 327  
 328          // Save a partial response.
 329          $this->process_submission(array('p1' => '1', 'p2' => '0', 'p3' => '0'));
 330  
 331          // Verify.
 332          $this->check_current_state(question_state::$invalid);
 333          $this->check_current_mark(null);
 334          $this->check_current_output(
 335                  $this->get_contains_drop_box_expectation('1', 1, false),
 336                  $this->get_contains_drop_box_expectation('2', 2, false),
 337                  $this->get_contains_drop_box_expectation('3', 3, false),
 338                  $this->get_contains_hidden_expectation(
 339                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 340                  $this->get_contains_hidden_expectation(
 341                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 342                  $this->get_contains_hidden_expectation(
 343                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 344                  $this->get_does_not_contain_correctness_expectation(),
 345                  $this->get_does_not_contain_feedback_expectation());
 346  
 347          // Finish the attempt.
 348          $this->quba->finish_all_questions();
 349  
 350          // Verify.
 351          $this->check_current_state(question_state::$gradedpartial);
 352          $this->check_current_mark(1);
 353          $this->check_current_output(
 354                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 355                  $this->get_contains_drop_box_expectation('2', 2, true, 'incorrect'),
 356                  $this->get_contains_drop_box_expectation('3', 3, true, 'incorrect'),
 357                  $this->get_contains_partcorrect_expectation());
 358      }
 359  
 360      public function test_interactive_grading() {
 361  
 362          // Create a drag-and-drop question.
 363          $dd = test_question_maker::make_question('ddwtos');
 364          $dd->hints = array(
 365              new question_hint_with_parts(1, 'This is the first hint.',
 366                      FORMAT_MOODLE, true, true),
 367              new question_hint_with_parts(2, 'This is the second hint.',
 368                      FORMAT_MOODLE, true, true),
 369          );
 370          $dd->shufflechoices = false;
 371          $this->start_attempt_at_question($dd, 'interactive', 9);
 372  
 373          // Check the initial state.
 374          $this->check_current_state(question_state::$todo);
 375          $this->check_current_mark(null);
 376          $this->assertEquals('interactivecountback',
 377                  $this->quba->get_question_attempt($this->slot)->get_behaviour_name());
 378          $this->check_current_output(
 379                  $this->get_contains_drop_box_expectation('1', 1, false),
 380                  $this->get_contains_drop_box_expectation('2', 2, false),
 381                  $this->get_contains_drop_box_expectation('3', 3, false),
 382                  $this->get_contains_hidden_expectation(
 383                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 384                  $this->get_contains_hidden_expectation(
 385                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 386                  $this->get_contains_hidden_expectation(
 387                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 388                  $this->get_contains_submit_button_expectation(true),
 389                  $this->get_does_not_contain_feedback_expectation(),
 390                  $this->get_tries_remaining_expectation(3),
 391                  $this->get_does_not_contain_num_parts_correct(),
 392                  $this->get_no_hint_visible_expectation());
 393  
 394          // Submit an response with the first two parts right.
 395          $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '2', '-submit' => 1));
 396  
 397          // Verify.
 398          $this->check_current_state(question_state::$todo);
 399          $this->check_current_mark(null);
 400          $this->check_current_output(
 401                  $this->get_contains_drop_box_expectation('1', 1, true),
 402                  $this->get_contains_drop_box_expectation('2', 2, true),
 403                  $this->get_contains_drop_box_expectation('3', 3, true),
 404                  $this->get_does_not_contain_submit_button_expectation(),
 405                  $this->get_contains_try_again_button_expectation(true),
 406                  $this->get_does_not_contain_correctness_expectation(),
 407                  $this->get_contains_hint_expectation('This is the first hint'),
 408                  $this->get_contains_num_parts_correct(2),
 409                  $this->get_contains_standard_partiallycorrect_combined_feedback_expectation(),
 410                  $this->get_contains_hidden_expectation(
 411                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 412                  $this->get_contains_hidden_expectation(
 413                          $this->quba->get_field_prefix($this->slot) . 'p2', '1'),
 414                  $this->get_contains_hidden_expectation(
 415                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'));
 416  
 417          // Check that extract responses will return the reset data.
 418          $prefix = $this->quba->get_field_prefix($this->slot);
 419          $this->assertEquals(array('p1' => '1', 'p2' => '1'),
 420                  $this->quba->extract_responses($this->slot,
 421                  array($prefix . 'p1' => '1', $prefix . 'p2' => '1', '-tryagain' => 1)));
 422  
 423          // Do try again.
 424          $this->process_submission(array('p1' => '1', 'p2' => '1', '-tryagain' => 1));
 425  
 426          // Verify.
 427          $this->check_current_state(question_state::$todo);
 428          $this->check_current_mark(null);
 429          $this->check_current_output(
 430                  $this->get_contains_drop_box_expectation('1', 1, false),
 431                  $this->get_contains_drop_box_expectation('2', 2, false),
 432                  $this->get_contains_drop_box_expectation('3', 3, false),
 433                  $this->get_contains_hidden_expectation(
 434                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 435                  $this->get_contains_hidden_expectation(
 436                          $this->quba->get_field_prefix($this->slot) . 'p2', '1'),
 437                  $this->get_contains_hidden_expectation(
 438                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 439                  $this->get_contains_submit_button_expectation(true),
 440                  $this->get_does_not_contain_try_again_button_expectation(),
 441                  $this->get_does_not_contain_correctness_expectation(),
 442                  $this->get_does_not_contain_feedback_expectation(),
 443                  $this->get_tries_remaining_expectation(2),
 444                  $this->get_no_hint_visible_expectation());
 445  
 446          // Submit an response with the first and last parts right.
 447          $this->process_submission(array('p1' => '1', 'p2' => '2', 'p3' => '1', '-submit' => 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_drop_box_expectation('1', 1, true),
 454                  $this->get_contains_drop_box_expectation('2', 2, true),
 455                  $this->get_contains_drop_box_expectation('3', 3, true),
 456                  $this->get_does_not_contain_submit_button_expectation(),
 457                  $this->get_contains_try_again_button_expectation(true),
 458                  $this->get_does_not_contain_correctness_expectation(),
 459                  $this->get_contains_hint_expectation('This is the second hint'),
 460                  $this->get_contains_num_parts_correct(2),
 461                  $this->get_contains_standard_partiallycorrect_combined_feedback_expectation(),
 462                  $this->get_contains_hidden_expectation(
 463                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 464                  $this->get_contains_hidden_expectation(
 465                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 466                  $this->get_contains_hidden_expectation(
 467                          $this->quba->get_field_prefix($this->slot) . 'p3', '1'));
 468  
 469          // Do try again.
 470          $this->process_submission(array('p1' => '1', 'p3' => '1', '-tryagain' => 1));
 471  
 472          // Verify.
 473          $this->check_current_state(question_state::$todo);
 474          $this->check_current_mark(null);
 475          $this->check_current_output(
 476                  $this->get_contains_drop_box_expectation('1', 1, false),
 477                  $this->get_contains_drop_box_expectation('2', 2, false),
 478                  $this->get_contains_drop_box_expectation('3', 3, false),
 479                  $this->get_contains_hidden_expectation(
 480                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 481                  $this->get_contains_hidden_expectation(
 482                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 483                  $this->get_contains_hidden_expectation(
 484                          $this->quba->get_field_prefix($this->slot) . 'p3', '1'),
 485                  $this->get_contains_submit_button_expectation(true),
 486                  $this->get_does_not_contain_try_again_button_expectation(),
 487                  $this->get_does_not_contain_correctness_expectation(),
 488                  $this->get_does_not_contain_feedback_expectation(),
 489                  $this->get_tries_remaining_expectation(1),
 490                  $this->get_no_hint_visible_expectation());
 491  
 492          // Submit the right answer.
 493          $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '1', '-submit' => 1));
 494  
 495          // Verify.
 496          $this->check_current_state(question_state::$gradedright);
 497          $this->check_current_mark(6);
 498          $this->check_current_output(
 499                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 500                  $this->get_contains_drop_box_expectation('2', 2, true, 'correct'),
 501                  $this->get_contains_drop_box_expectation('3', 3, true, 'correct'),
 502                  $this->get_does_not_contain_submit_button_expectation(),
 503                  $this->get_does_not_contain_try_again_button_expectation(),
 504                  $this->get_contains_correct_expectation(),
 505                  $this->get_no_hint_visible_expectation(),
 506                  $this->get_does_not_contain_num_parts_correct(),
 507                  $this->get_contains_standard_correct_combined_feedback_expectation(),
 508                  $this->get_contains_hidden_expectation(
 509                          $this->quba->get_field_prefix($this->slot) . 'p1', '1'),
 510                  $this->get_contains_hidden_expectation(
 511                          $this->quba->get_field_prefix($this->slot) . 'p2', '1'),
 512                  $this->get_contains_hidden_expectation(
 513                          $this->quba->get_field_prefix($this->slot) . 'p3', '1'));
 514      }
 515  
 516      public function test_interactive_correct_no_submit() {
 517  
 518          // Create a drag-and-drop question.
 519          $dd = test_question_maker::make_question('ddwtos');
 520          $dd->hints = array(
 521              new question_hint_with_parts(23, 'This is the first hint.',
 522                      FORMAT_MOODLE, false, false),
 523              new question_hint_with_parts(24, 'This is the second hint.',
 524                      FORMAT_MOODLE, true, true),
 525          );
 526          $dd->shufflechoices = false;
 527          $this->start_attempt_at_question($dd, 'interactive', 3);
 528  
 529          // Check the initial state.
 530          $this->check_current_state(question_state::$todo);
 531          $this->check_current_mark(null);
 532          $this->check_current_output(
 533                  $this->get_contains_drop_box_expectation('1', 1, false),
 534                  $this->get_contains_drop_box_expectation('2', 2, false),
 535                  $this->get_contains_drop_box_expectation('3', 3, false),
 536                  $this->get_contains_hidden_expectation(
 537                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 538                  $this->get_contains_hidden_expectation(
 539                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 540                  $this->get_contains_hidden_expectation(
 541                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 542                  $this->get_contains_submit_button_expectation(true),
 543                  $this->get_does_not_contain_feedback_expectation(),
 544                  $this->get_tries_remaining_expectation(3),
 545                  $this->get_no_hint_visible_expectation());
 546  
 547          // Save the right answer.
 548          $this->process_submission(array('p1' => '1', 'p2' => '1', 'p3' => '1'));
 549  
 550          // Finish the attempt without clicking check.
 551          $this->quba->finish_all_questions();
 552  
 553          // Verify.
 554          $this->check_current_state(question_state::$gradedright);
 555          $this->check_current_mark(3);
 556          $this->check_current_output(
 557                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 558                  $this->get_contains_drop_box_expectation('2', 2, true, 'correct'),
 559                  $this->get_contains_drop_box_expectation('3', 3, true, 'correct'),
 560                  $this->get_does_not_contain_submit_button_expectation(),
 561                  $this->get_contains_correct_expectation(),
 562                  $this->get_no_hint_visible_expectation());
 563  
 564          // Check regrading does not mess anything up.
 565          $this->quba->regrade_all_questions();
 566  
 567          // Verify.
 568          $this->check_current_state(question_state::$gradedright);
 569          $this->check_current_mark(3);
 570      }
 571  
 572      public function test_interactive_partial_no_submit() {
 573  
 574          // Create a drag-and-drop question.
 575          $dd = test_question_maker::make_question('ddwtos');
 576          $dd->hints = array(
 577              new question_hint_with_parts(23, 'This is the first hint.',
 578                      FORMAT_MOODLE, false, false),
 579              new question_hint_with_parts(24, 'This is the second hint.',
 580                      FORMAT_MOODLE, true, true),
 581          );
 582          $dd->shufflechoices = false;
 583          $this->start_attempt_at_question($dd, 'interactive', 3);
 584  
 585          // Check the initial state.
 586          $this->check_current_state(question_state::$todo);
 587          $this->check_current_mark(null);
 588          $this->check_current_output(
 589                  $this->get_contains_drop_box_expectation('1', 1, false),
 590                  $this->get_contains_drop_box_expectation('2', 2, false),
 591                  $this->get_contains_drop_box_expectation('3', 3, false),
 592                  $this->get_contains_hidden_expectation(
 593                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 594                  $this->get_contains_hidden_expectation(
 595                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 596                  $this->get_contains_hidden_expectation(
 597                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 598                  $this->get_contains_submit_button_expectation(true),
 599                  $this->get_does_not_contain_feedback_expectation(),
 600                  $this->get_tries_remaining_expectation(3),
 601                  $this->get_no_hint_visible_expectation());
 602  
 603          // Save the a partially right answer.
 604          $this->process_submission(array('p1' => '1', 'p2' => '2', 'p3' => '2'));
 605  
 606          // Finish the attempt without clicking check.
 607          $this->quba->finish_all_questions();
 608  
 609          // Verify.
 610          $this->check_current_state(question_state::$gradedpartial);
 611          $this->check_current_mark(1);
 612          $this->check_current_output(
 613                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 614                  $this->get_contains_drop_box_expectation('2', 2, true, 'incorrect'),
 615                  $this->get_contains_drop_box_expectation('3', 3, true, 'incorrect'),
 616                  $this->get_does_not_contain_submit_button_expectation(),
 617                  $this->get_contains_partcorrect_expectation(),
 618                  $this->get_no_hint_visible_expectation());
 619  
 620          // Check regrading does not mess anything up.
 621          $this->quba->regrade_all_questions();
 622  
 623          // Verify.
 624          $this->check_current_state(question_state::$gradedpartial);
 625          $this->check_current_mark(1);
 626      }
 627  
 628      public function test_interactive_no_right_clears() {
 629  
 630          // Create a drag-and-drop question.
 631          $dd = test_question_maker::make_question('ddwtos');
 632          $dd->hints = array(
 633              new question_hint_with_parts(23, 'This is the first hint.', FORMAT_MOODLE, false, true),
 634              new question_hint_with_parts(24, 'This is the second hint.', FORMAT_MOODLE, true, true),
 635          );
 636          $dd->shufflechoices = false;
 637          $this->start_attempt_at_question($dd, 'interactive', 3);
 638  
 639          // Check the initial state.
 640          $this->check_current_state(question_state::$todo);
 641          $this->check_current_mark(null);
 642          $this->check_current_output(
 643                  $this->get_contains_marked_out_of_summary(),
 644                  $this->get_contains_drop_box_expectation('1', 1, false),
 645                  $this->get_contains_drop_box_expectation('2', 2, false),
 646                  $this->get_contains_drop_box_expectation('3', 3, false),
 647                  $this->get_contains_hidden_expectation(
 648                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 649                  $this->get_contains_hidden_expectation(
 650                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 651                  $this->get_contains_hidden_expectation(
 652                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 653                  $this->get_contains_submit_button_expectation(true),
 654                  $this->get_does_not_contain_feedback_expectation(),
 655                  $this->get_tries_remaining_expectation(3),
 656                  $this->get_no_hint_visible_expectation());
 657  
 658          // Save the a completely wrong answer.
 659          $this->process_submission(array('p1' => '2', 'p2' => '2', 'p3' => '2', '-submit' => 1));
 660  
 661          // Verify.
 662          $this->check_current_state(question_state::$todo);
 663          $this->check_current_mark(null);
 664          $this->check_current_output(
 665                  $this->get_contains_marked_out_of_summary(),
 666                  $this->get_contains_drop_box_expectation('1', 1, true),
 667                  $this->get_contains_drop_box_expectation('2', 2, true),
 668                  $this->get_contains_drop_box_expectation('3', 3, true),
 669                  $this->get_does_not_contain_submit_button_expectation(),
 670                  $this->get_contains_hint_expectation('This is the first hint'));
 671  
 672          // Do try again.
 673          $this->process_submission(array('p1' => '0', 'p2' => '0', 'p3' => '0', '-tryagain' => 1));
 674  
 675          // Check that all the wrong answers have been cleared.
 676          $this->check_current_state(question_state::$todo);
 677          $this->check_current_mark(null);
 678          $this->check_current_output(
 679                  $this->get_contains_marked_out_of_summary(),
 680                  $this->get_contains_drop_box_expectation('1', 1, false),
 681                  $this->get_contains_drop_box_expectation('2', 2, false),
 682                  $this->get_contains_drop_box_expectation('3', 3, false),
 683                  $this->get_contains_hidden_expectation(
 684                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 685                  $this->get_contains_hidden_expectation(
 686                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 687                  $this->get_contains_hidden_expectation(
 688                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 689                  $this->get_contains_submit_button_expectation(true),
 690                  $this->get_does_not_contain_feedback_expectation(),
 691                  $this->get_tries_remaining_expectation(2),
 692                  $this->get_no_hint_visible_expectation());
 693      }
 694  
 695      public function test_display_of_right_answer_when_shuffled() {
 696  
 697          // Create a drag-and-drop question.
 698          $dd = test_question_maker::make_question('ddwtos');
 699          $this->start_attempt_at_question($dd, 'deferredfeedback', 3);
 700  
 701          // Check the initial state.
 702          $this->check_current_state(question_state::$todo);
 703          $this->check_current_mark(null);
 704          $this->check_current_output(
 705                  $this->get_contains_drop_box_expectation('1', 1, false),
 706                  $this->get_contains_drop_box_expectation('2', 2, false),
 707                  $this->get_contains_drop_box_expectation('3', 3, false),
 708                  $this->get_contains_hidden_expectation(
 709                          $this->quba->get_field_prefix($this->slot) . 'p1', '0'),
 710                  $this->get_contains_hidden_expectation(
 711                          $this->quba->get_field_prefix($this->slot) . 'p2', '0'),
 712                  $this->get_contains_hidden_expectation(
 713                          $this->quba->get_field_prefix($this->slot) . 'p3', '0'),
 714                  $this->get_does_not_contain_feedback_expectation());
 715  
 716          // Save a partial answer.
 717          $this->process_submission($dd->get_correct_response());
 718  
 719          // Verify.
 720          $this->check_current_state(question_state::$complete);
 721          $this->check_current_mark(null);
 722          $this->check_current_output(
 723                  $this->get_contains_drop_box_expectation('1', 1, false),
 724                  $this->get_contains_drop_box_expectation('2', 2, false),
 725                  $this->get_contains_drop_box_expectation('3', 3, false),
 726                  $this->get_contains_hidden_expectation(
 727                          $this->quba->get_field_prefix($this->slot) . 'p1',
 728                                  $dd->get_right_choice_for(1)),
 729                  $this->get_contains_hidden_expectation(
 730                          $this->quba->get_field_prefix($this->slot) . 'p2',
 731                                  $dd->get_right_choice_for(2)),
 732                  $this->get_contains_hidden_expectation(
 733                          $this->quba->get_field_prefix($this->slot) . 'p3',
 734                                  $dd->get_right_choice_for(3)),
 735                  $this->get_does_not_contain_correctness_expectation(),
 736                  $this->get_does_not_contain_feedback_expectation());
 737  
 738          // Finish the attempt.
 739          $this->quba->finish_all_questions();
 740  
 741          // Verify.
 742          $this->displayoptions->rightanswer = question_display_options::VISIBLE;
 743          $this->assertEquals('{quick} {fox} {lazy}', $dd->get_right_answer_summary());
 744          $this->check_current_state(question_state::$gradedright);
 745          $this->check_current_mark(3);
 746          $this->check_current_output(
 747                  $this->get_contains_drop_box_expectation('1', 1, true, 'correct'),
 748                  $this->get_contains_drop_box_expectation('2', 2, true, 'correct'),
 749                  $this->get_contains_drop_box_expectation('3', 3, true, 'correct'),
 750                  $this->get_contains_correct_expectation(),
 751                  new question_pattern_expectation('/' .
 752                          preg_quote('The [quick] brown [fox] jumped over the [lazy] dog.', '/') . '/'));
 753      }
 754  }