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