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.
   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   * Tests of the upgrade to the new Moodle question engine for attempts at
  19   * match questions.
  20   *
  21   * @package   qtype_match
  22   * @copyright 2009 The Open University
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->dirroot . '/question/engine/upgrade/tests/helper.php');
  31  
  32  
  33  /**
  34   * Testing the upgrade of match question attempts.
  35   *
  36   * @copyright 2009 The Open University
  37   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class qtype_match_attempt_upgrader_test extends question_attempt_upgrader_test_base {
  40  
  41      public function test_match_deferredfeedback_history6220() {
  42          $quiz = (object) array(
  43              'id' => '72',
  44              'course' => '1181',
  45              'name' => 'Study Guide 4 Quiz',
  46              'intro' => '',
  47              'introformat' => FORMAT_HTML,
  48              'questiondecimalpoints' => '-1',
  49              'showuserpicture' => '1',
  50              'showblocks' => '1',
  51              'timeopen' => '0',
  52              'timeclose' => '0',
  53              'preferredbehaviour' => 'deferredfeedback',
  54              'attempts' => '0',
  55              'attemptonlast' => '1',
  56              'grademethod' => '1',
  57              'decimalpoints' => '2',
  58              'review' => '71760879',
  59              'questionsperpage' => '2',
  60              'shufflequestions' => '0',
  61              'shuffleanswers' => '0',
  62              'sumgrades' => '48',
  63              'grade' => '48',
  64              'timecreated' => '0',
  65              'timemodified' => '1170427370',
  66              'password' => '',
  67              'subnet' => '',
  68              'popup' => '0',
  69              'delay1' => '0',
  70              'delay2' => '0',
  71              'timelimit' => '0',
  72          );
  73          $attempt = (object) array(
  74              'id' => '3562',
  75              'uniqueid' => '3562',
  76              'quiz' => '72',
  77              'userid' => '91483',
  78              'attempt' => '6',
  79              'sumgrades' => '43',
  80              'timestart' => '1177419915',
  81              'timefinish' => '1177419962',
  82              'timemodified' => '1168015476',
  83              'layout' => '689,690,0,691,692,0,693,694,0,695,696,0,697,698,0',
  84              'preview' => '0',
  85          );
  86          $question = (object) array(
  87              'id' => '695',
  88              'category' => '65',
  89              'parent' => '0',
  90              'name' => 'Question 7',
  91              'questiontext' => '<p>Associate the appropriate definition with each term.</p>',
  92              'questiontextformat' => '1',
  93              'defaultmark' => '1',
  94              'penalty' => '0',
  95              'qtype' => 'match',
  96              'length' => '1',
  97              'stamp' => 'learn.open.ac.uk+061123110024+a0RsuG',
  98              'version' => 'learn.open.ac.uk+061123163015+Oe63zC',
  99              'hidden' => '0',
 100              'generalfeedback' => 'For further information about this question see Study Guide 4 SAQ 3.1',
 101              'generalfeedbackformat' => '1',
 102              'timecreated' => '0',
 103              'timemodified' => '0',
 104              'createdby' => null,
 105              'modifiedby' => null,
 106              'unlimited' => null,
 107              'maxmark' => '3',
 108              'options' => (object) array(
 109                  'id' => '27',
 110                  'questionid' => '695',
 111                  'subquestions' => array(
 112                      148 => (object) array(
 113                          'questionid' => '695',
 114                          'questiontext' => 'Active adjacent system',
 115                          'answertext' => 'A system that interacts with or participates in the work.',
 116                          'id' => 148,
 117                      ),
 118                      149 => (object) array(
 119                          'questionid' => '695',
 120                          'questiontext' => 'Autonomous adjacent system',
 121                          'answertext' => 'An external entity that acts independently of the work under study.',
 122                          'id' => 149,
 123                      ),
 124                      150 => (object) array(
 125                          'questionid' => '695',
 126                          'questiontext' => 'Cooperative adjacent system',
 127                          'answertext' => 'A system that is involved in the response to a business event.',
 128                          'id' => 150,
 129                      ),
 130                      151 => (object) array(
 131                          'questionid' => '695',
 132                          'questiontext' => '',
 133                          'answertext' => 'A system which does not supply or receive data from the work.',
 134                          'id' => 151,
 135                      ),
 136                      152 => (object) array(
 137                          'questionid' => '695',
 138                          'questiontext' => '',
 139                          'answertext' => 'An external entity that performs part of the work under study.',
 140                          'id' => 152,
 141                      ),
 142                  ),
 143                  'shuffleanswers' => '1',
 144                  'correctfeedback' => '',
 145                  'partiallycorrectfeedback' => '',
 146                  'incorrectfeedback' => '',
 147                  'correctresponsesfeedback' => '0',
 148              ),
 149              'hints' => false,
 150          );
 151          $qsession = (object) array(
 152              'id' => '33092',
 153              'attemptid' => '3562',
 154              'questionid' => '695',
 155              'newest' => '79626',
 156              'newgraded' => '79626',
 157              'sumpenalty' => '0',
 158              'manualcomment' => '',
 159              'manualcommentformat' => '1',
 160              'flagged' => '1',
 161          );
 162          $qstates = array(
 163              79604 => (object) array(
 164                  'attempt' => '3562',
 165                  'question' => '695',
 166                  'originalquestion' => '0',
 167                  'seq_number' => '0',
 168                  'answer' => '148-0,149-0,150-0,151-0,152-0',
 169                  'timestamp' => '1177419915',
 170                  'event' => '0',
 171                  'grade' => '0',
 172                  'raw_grade' => '0',
 173                  'penalty' => '0',
 174                  'id' => 79604,
 175              ),
 176              79614 => (object) array(
 177                  'attempt' => '3562',
 178                  'question' => '695',
 179                  'originalquestion' => '0',
 180                  'seq_number' => '1',
 181                  'answer' => '148-148,149-151,150-152,151-0,152-0',
 182                  'timestamp' => '1177419855',
 183                  'event' => '2',
 184                  'grade' => '0',
 185                  'raw_grade' => '1',
 186                  'penalty' => '0',
 187                  'id' => 79614,
 188              ),
 189              79619 => (object) array(
 190                  'attempt' => '3562',
 191                  'question' => '695',
 192                  'originalquestion' => '0',
 193                  'seq_number' => '2',
 194                  'answer' => '148-148,149-149,150-150,151-0,152-0',
 195                  'timestamp' => '1177419956',
 196                  'event' => '2',
 197                  'grade' => '0',
 198                  'raw_grade' => '3',
 199                  'penalty' => '0',
 200                  'id' => 79619,
 201              ),
 202              79626 => (object) array(
 203                  'attempt' => '3562',
 204                  'question' => '695',
 205                  'originalquestion' => '0',
 206                  'seq_number' => '3',
 207                  'answer' => '148-148,149-149,150-150,151-0,152-0',
 208                  'timestamp' => '1177419956',
 209                  'event' => '6',
 210                  'grade' => '3',
 211                  'raw_grade' => '3',
 212                  'penalty' => '0',
 213                  'id' => 79626,
 214              ),
 215          );
 216  
 217          $qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
 218  
 219          $expectedqa = (object) array(
 220              'behaviour' => 'deferredfeedback',
 221              'questionid' => 695,
 222              'variant' => 1,
 223              'maxmark' => 3,
 224              'minfraction' => 0,
 225              'maxfraction' => 1,
 226              'flagged' => 0,
 227              'questionsummary' => 'Associate the appropriate definition with each term. ' .
 228                      '{Active adjacent system; Autonomous adjacent system; ' .
 229                      'Cooperative adjacent system} -> {A system that interacts with ' .
 230                      'or participates in the work.; An external entity that acts ' .
 231                      'independently of the work under study.; A system that is involved ' .
 232                      'in the response to a business event.; A system which does not supply ' .
 233                      'or receive data from the work.; An external entity that performs part ' .
 234                      'of the work under study.}',
 235              'rightanswer' => 'Active adjacent system -> A system that interacts with ' .
 236                      'or participates in the work.; Autonomous adjacent system -> ' .
 237                      'An external entity that acts independently of the work under study.; ' .
 238                      'Cooperative adjacent system -> A system that is involved in the response ' .
 239                      'to a business event.',
 240              'responsesummary' => 'Active adjacent system -> A system that interacts with ' .
 241                      'or participates in the work.; Autonomous adjacent system -> ' .
 242                      'An external entity that acts independently of the work under study.; ' .
 243                      'Cooperative adjacent system -> A system that is involved in the response ' .
 244                      'to a business event.',
 245              'timemodified' => 1177419956,
 246              'steps' => array(
 247                  0 => (object) array(
 248                      'sequencenumber' => 0,
 249                      'state' => 'todo',
 250                      'fraction' => null,
 251                      'timecreated' => 1177419915,
 252                      'userid' => 91483,
 253                      'data' => array('_stemorder' => '148,149,150',
 254                              '_choiceorder' => 'todo - see below'),
 255                  ),
 256                  1 => (object) array(
 257                      'sequencenumber' => 1,
 258                      'state' => 'complete',
 259                      'fraction' => null,
 260                      'timecreated' => 1177419855,
 261                      'userid' => 91483,
 262                      'data' => array('sub0' => 148, 'sub1' => 151, 'sub2' => 152),
 263                  ),
 264                  2 => (object) array(
 265                      'sequencenumber' => 2,
 266                      'state' => 'complete',
 267                      'fraction' => null,
 268                      'timecreated' => 1177419956,
 269                      'userid' => 91483,
 270                      'data' => array('sub0' => 148, 'sub1' => 149, 'sub2' => 150),
 271                  ),
 272                  3 => (object) array(
 273                      'sequencenumber' => 3,
 274                      'state' => 'gradedright',
 275                      'fraction' => 1,
 276                      'timecreated' => 1177419956,
 277                      'userid' => 91483,
 278                      'data' => array('sub0' => 148, 'sub1' => 149, 'sub2' => 150, '-finish' => 1),
 279                  ),
 280              ),
 281          );
 282  
 283          // This is a random thing, so just set expected to actual.
 284          $expectedqa->steps[0]->data['_choiceorder'] = $qa->steps[0]->data['_choiceorder'];
 285          $order = explode(',', $qa->steps[0]->data['_choiceorder']);
 286          $order = array_combine(array_values($order), array_keys($order));
 287          for ($i = 1; $i <= 3; $i++) {
 288              for ($sub = 0; $sub < 3; $sub++) {
 289                  $expectedqa->steps[$i]->data['sub' . $sub] =
 290                          $order[$expectedqa->steps[$i]->data['sub' . $sub]] + 1;
 291              }
 292          }
 293  
 294          $this->compare_qas($expectedqa, $qa);
 295      }
 296  
 297      public function test_match_deferredfeedback_history60() {
 298          $quiz = (object) array(
 299              'id' => '60',
 300              'course' => '2304',
 301              'name' => 'Types of resources available quiz',
 302              'intro' => 'This quiz covers the different types of information resources available ' .
 303                      'and how to select which is most appropriate. ',
 304              'introformat' => FORMAT_HTML,
 305              'questiondecimalpoints' => '-1',
 306              'showuserpicture' => '1',
 307              'showblocks' => '1',
 308              'timeopen' => '1164153600',
 309              'timeclose' => '1606003200',
 310              'preferredbehaviour' => 'deferredfeedback',
 311              'attempts' => '0',
 312              'attemptonlast' => '0',
 313              'grademethod' => '1',
 314              'decimalpoints' => '3',
 315              'review' => '71752557',
 316              'questionsperpage' => '1',
 317              'shufflequestions' => '0',
 318              'shuffleanswers' => '0',
 319              'sumgrades' => '5',
 320              'grade' => '10',
 321              'timecreated' => '0',
 322              'timemodified' => '1170245956',
 323              'password' => '',
 324              'subnet' => '',
 325              'popup' => '0',
 326              'delay1' => '0',
 327              'delay2' => '0',
 328              'timelimit' => '0',
 329          );
 330          $attempt = (object) array(
 331              'id' => '1065',
 332              'uniqueid' => '1065',
 333              'quiz' => '60',
 334              'userid' => '182682',
 335              'attempt' => '1',
 336              'sumgrades' => '3.99998',
 337              'timestart' => '1168267317',
 338              'timefinish' => '1168267508',
 339              'timemodified' => '1168267508',
 340              'layout' => '509,510,511,738,514,0',
 341              'preview' => '0',
 342          );
 343          $question = (object) array(
 344              'id' => '738',
 345              'category' => '60',
 346              'parent' => '0',
 347              'name' => 'TR004',
 348              'questiontext' => '<p>Which of the following statements about subject gateways are true, and which are false? </p>',
 349              'questiontextformat' => '1',
 350              'defaultmark' => '1',
 351              'penalty' => '0.1',
 352              'qtype' => 'match',
 353              'length' => '1',
 354              'stamp' => 'learn.open.ac.uk+061128151507+CLevuJ',
 355              'version' => 'learn.open.ac.uk+070108115531+VvJurj',
 356              'hidden' => '0',
 357              'generalfeedback' => '<UL><LI>Subject gateways provide links to sites that have been quality checked = True</LI>
 358          <LI>Subject gateways offer more variety than search engines = False</LI>
 359          <LI>Subject gateways index websites automatically = False</LI>
 360          <LI>Subject gateways can provide a more direct route to websites containing academic content = True</LI>
 361          </UL>',
 362              'generalfeedbackformat' => '1',
 363              'timecreated' => '0',
 364              'timemodified' => '0',
 365              'createdby' => null,
 366              'modifiedby' => null,
 367              'unlimited' => null,
 368              'maxmark' => '1',
 369              'options' => (object) array(
 370                  'id' => '35',
 371                  'questionid' => '738',
 372                  'subquestions' => array(
 373                      213 => (object) array(
 374                          'questionid' => '738',
 375                          'questiontext' => 'Subject gateways provide links to sites that have been quality checked ',
 376                          'answertext' => 'True',
 377                          'id' => 213,
 378                      ),
 379                      214 => (object) array(
 380                          'questionid' => '738',
 381                          'questiontext' => 'Subject gateways offer more variety than search engines ',
 382                          'answertext' => 'False',
 383                          'id' => 214,
 384                      ),
 385                      215 => (object) array(
 386                          'questionid' => '738',
 387                          'questiontext' => 'Subject gateways index websites automatically',
 388                          'answertext' => 'False',
 389                          'id' => 215,
 390                      ),
 391                      216 => (object) array(
 392                          'questionid' => '738',
 393                          'questiontext' => 'Subject gateways can provide a more direct route ' .
 394                                  'to websites containing academic content ',
 395                          'answertext' => 'True',
 396                          'id' => 216,
 397                      ),
 398                  ),
 399                  'shuffleanswers' => '1',
 400                  'correctfeedback' => '',
 401                  'partiallycorrectfeedback' => '',
 402                  'incorrectfeedback' => '',
 403                  'correctresponsesfeedback' => '0',
 404              ),
 405              'hints' => false,
 406          );
 407          $qsession = (object) array(
 408              'id' => '9258',
 409              'attemptid' => '1065',
 410              'questionid' => '738',
 411              'newest' => '24966',
 412              'newgraded' => '24966',
 413              'sumpenalty' => '0',
 414              'manualcomment' => '',
 415              'manualcommentformat' => '1',
 416              'flagged' => '1',
 417          );
 418          $qstates = array(
 419              24961 => (object) array(
 420                  'attempt' => '1065',
 421                  'question' => '738',
 422                  'originalquestion' => '0',
 423                  'seq_number' => '0',
 424                  'answer' => '213-0,214-0,215-0,216-0',
 425                  'timestamp' => '1168267317',
 426                  'event' => '0',
 427                  'grade' => '0',
 428                  'raw_grade' => '0',
 429                  'penalty' => '0',
 430                  'id' => 24961,
 431              ),
 432              24966 => (object) array(
 433                  'attempt' => '1065',
 434                  'question' => '738',
 435                  'originalquestion' => '0',
 436                  'seq_number' => '1',
 437                  'answer' => '213-213,214-214,215-215,216-216',
 438                  'timestamp' => '1168267508',
 439                  'event' => '6',
 440                  'grade' => '1',
 441                  'raw_grade' => '1',
 442                  'penalty' => '0.1',
 443                  'id' => 24966,
 444              ),
 445          );
 446  
 447          $qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
 448  
 449          $expectedqa = (object) array(
 450              'behaviour' => 'deferredfeedback',
 451              'questionid' => 738,
 452              'variant' => 1,
 453              'maxmark' => 1,
 454              'minfraction' => 0,
 455              'maxfraction' => 1,
 456              'flagged' => 0,
 457              'questionsummary' => 'Which of the following statements about subject ' .
 458                      'gateways are true, and which are false? {Subject gateways ' .
 459                      'provide links to sites that have been quality checked; ' .
 460                      'Subject gateways offer more variety than search engines; ' .
 461                      'Subject gateways index websites automatically; ' .
 462                      'Subject gateways can provide a more direct route to websites containing academic content} -> ' .
 463                      '{True; False}',
 464              'rightanswer' => 'Subject gateways provide links to sites that have been quality checked -> True; ' .
 465                      'Subject gateways offer more variety than search engines -> False; ' .
 466                      'Subject gateways index websites automatically -> False; ' .
 467                      'Subject gateways can provide a more direct route to websites containing academic content -> True',
 468              'responsesummary' => 'Subject gateways provide links to sites that have been quality checked -> True; ' .
 469                      'Subject gateways offer more variety than search engines -> False; ' .
 470                      'Subject gateways index websites automatically -> False; ' .
 471                      'Subject gateways can provide a more direct route to websites containing academic content -> True',
 472              'timemodified' => 1168267508,
 473              'steps' => array(
 474                  0 => (object) array(
 475                      'sequencenumber' => 0,
 476                      'state' => 'todo',
 477                      'fraction' => null,
 478                      'timecreated' => 1168267317,
 479                      'userid' => 182682,
 480                      'data' => array('_stemorder' => '213,214,215,216', '_choiceorder' => 'todo - see below'),
 481                  ),
 482                  1 => (object) array(
 483                      'sequencenumber' => 1,
 484                      'state' => 'gradedright',
 485                      'fraction' => 1,
 486                      'timecreated' => 1168267508,
 487                      'userid' => 182682,
 488                      'data' => array('sub0' => 213, 'sub1' => 214, 'sub2' => 214, 'sub3' => 213, '-finish' => 1),
 489                  ),
 490              ),
 491          );
 492  
 493          // This is a random thing, so just set expected to actual.
 494          $expectedqa->steps[0]->data['_choiceorder'] = $qa->steps[0]->data['_choiceorder'];
 495          $order = explode(',', $qa->steps[0]->data['_choiceorder']);
 496          $order = array_combine(array_values($order), array_keys($order));
 497          for ($i = 1; $i <= 1; $i++) {
 498              for ($sub = 0; $sub < 4; $sub++) {
 499                  $expectedqa->steps[$i]->data['sub' . $sub] =
 500                          $order[$expectedqa->steps[$i]->data['sub' . $sub]] + 1;
 501              }
 502          }
 503  
 504          $this->compare_qas($expectedqa, $qa);
 505      }
 506  
 507      public function test_match_deferredfeedback_history622220() {
 508          $quiz = (object) array(
 509              'id' => '719',
 510              'course' => '3541',
 511              'name' => 'Types of resources quiz',
 512              'intro' => '',
 513              'introformat' => FORMAT_HTML,
 514              'questiondecimalpoints' => '-1',
 515              'showuserpicture' => '1',
 516              'showblocks' => '1',
 517              'timeopen' => '0',
 518              'timeclose' => '0',
 519              'preferredbehaviour' => 'deferredfeedback',
 520              'attempts' => '0',
 521              'attemptonlast' => '0',
 522              'grademethod' => '1',
 523              'decimalpoints' => '2',
 524              'review' => '71760879',
 525              'questionsperpage' => '1',
 526              'shufflequestions' => '0',
 527              'shuffleanswers' => '1',
 528              'sumgrades' => '5',
 529              'grade' => '10',
 530              'timecreated' => '0',
 531              'timemodified' => '1193678199',
 532              'password' => '',
 533              'subnet' => '',
 534              'popup' => '0',
 535              'delay1' => '0',
 536              'delay2' => '0',
 537              'timelimit' => '0',
 538          );
 539          $attempt = (object) array(
 540              'id' => '23777',
 541              'uniqueid' => '23777',
 542              'quiz' => '719',
 543              'userid' => '6584',
 544              'attempt' => '1',
 545              'sumgrades' => '3.91664',
 546              'timestart' => '1200506648',
 547              'timefinish' => '1200507571',
 548              'timemodified' => '1200506959',
 549              'layout' => '11163,0,11164,0,11165,0,11135,0,11166,0',
 550              'preview' => '0',
 551          );
 552          $question = (object) array(
 553              'id' => '11135',
 554              'category' => '675',
 555              'parent' => '0',
 556              'name' => 'TR004',
 557              'questiontext' => '<p>Which of the following statements about subject gateways are true, and which are false? </p>',
 558              'questiontextformat' => '0',
 559              'defaultmark' => '1',
 560              'penalty' => '0.1',
 561              'qtype' => 'match',
 562              'length' => '1',
 563              'stamp' => 'learn.open.ac.uk+071023110917+tqaM6z',
 564              'version' => 'learn.open.ac.uk+071023110917+Ia7Hpz',
 565              'hidden' => '0',
 566              'generalfeedback' => '<ul>
 567              <li>Subject gateways provide links to sites that have been quality checked = True </li>
 568   </ul>
 569   <p>All links in a subject gateway have been added by a knowledgeable subject specialist and ' .
 570                                  'so have to be of a certain quality to be added to the collection.</p>
 571   <ul>
 572              <li>Subject gateways offer more variety than search engines = False </li>
 573   </ul>
 574   <p>Subject gateways will most likely provide fewer links than a search engine, but this is because ' .
 575                                  'they are selected with a particular subject area in mind </p>
 576   <ul>
 577              <li>Subject gateways index websites automatically = False </li>
 578   </ul>
 579   <p>Subject gateways links are indexed by knowledgeable subject specialists rather than a machine. </p>
 580   <ul>
 581              <li>Subject gateways can provide a more direct route to websites containing academic content = True </li>
 582   </ul>
 583   <p>All links in a subject gateway have been added by a knowledgeable subject specialist ' .
 584                                  'and so you can find academic content easier than using a web search engine.</p>',
 585              'generalfeedbackformat' => '1',
 586              'timecreated' => '0',
 587              'timemodified' => '0',
 588              'createdby' => null,
 589              'modifiedby' => null,
 590              'unlimited' => null,
 591              'maxmark' => '1',
 592              'options' => (object) array(
 593                  'id' => '279',
 594                  'questionid' => '11135',
 595                  'subquestions' => array(
 596                      1632 => (object) array(
 597                          'questionid' => '11135',
 598                          'questiontext' => 'Subject gateways provide links to sites that have been quality checked',
 599                          'answertext' => 'True',
 600                          'id' => 1632,
 601                      ),
 602                      1633 => (object) array(
 603                          'questionid' => '11135',
 604                          'questiontext' => 'Subject gateways offer more variety than search engines',
 605                          'answertext' => 'False',
 606                          'id' => 1633,
 607                      ),
 608                      1634 => (object) array(
 609                          'questionid' => '11135',
 610                          'questiontext' => 'Subject gateways index websites automatically',
 611                          'answertext' => 'False',
 612                          'id' => 1634,
 613                      ),
 614                      1635 => (object) array(
 615                          'questionid' => '11135',
 616                          'questiontext' => 'Subject gateways can provide a more direct route to websites ' .
 617                                  'containing academic content',
 618                          'answertext' => 'True',
 619                          'id' => 1635,
 620                      ),
 621                  ),
 622                  'shuffleanswers' => '1',
 623                  'correctfeedback' => '',
 624                  'partiallycorrectfeedback' => '',
 625                  'incorrectfeedback' => '',
 626                  'correctresponsesfeedback' => '0',
 627              ),
 628              'hints' => false,
 629          );
 630          $qsession = (object) array(
 631              'id' => '356418',
 632              'attemptid' => '23777',
 633              'questionid' => '11135',
 634              'newest' => '862740',
 635              'newgraded' => '862740',
 636              'sumpenalty' => '0.1',
 637              'manualcomment' => '',
 638              'manualcommentformat' => '1',
 639              'flagged' => '1',
 640          );
 641          $qstates = array(
 642              862587 => (object) array(
 643                  'attempt' => '23777',
 644                  'question' => '11135',
 645                  'originalquestion' => '0',
 646                  'seq_number' => '0',
 647                  'answer' => '1633-0,1635-0,1634-0,1632-0',
 648                  'timestamp' => '1200506648',
 649                  'event' => '0',
 650                  'grade' => '0',
 651                  'raw_grade' => '0',
 652                  'penalty' => '0',
 653                  'id' => 862587,
 654              ),
 655              862638 => (object) array(
 656                  'attempt' => '23777',
 657                  'question' => '11135',
 658                  'originalquestion' => '0',
 659                  'seq_number' => '1',
 660                  'answer' => '1633-1633,1635-1635,1634-0,1632-1632',
 661                  'timestamp' => '1200507025',
 662                  'event' => '2',
 663                  'grade' => '0',
 664                  'raw_grade' => '0.75',
 665                  'penalty' => '0.1',
 666                  'id' => 862638,
 667              ),
 668              862668 => (object) array(
 669                  'attempt' => '23777',
 670                  'question' => '11135',
 671                  'originalquestion' => '0',
 672                  'seq_number' => '2',
 673                  'answer' => '1633-1633,1635-1635,1634-0,1632-1632',
 674                  'timestamp' => '1200507125',
 675                  'event' => '2',
 676                  'grade' => '0',
 677                  'raw_grade' => '0.75',
 678                  'penalty' => '0.1',
 679                  'id' => 862668,
 680              ),
 681              862673 => (object) array(
 682                  'attempt' => '23777',
 683                  'question' => '11135',
 684                  'originalquestion' => '0',
 685                  'seq_number' => '3',
 686                  'answer' => '1633-1633,1635-1635,1634-0,1632-1632',
 687                  'timestamp' => '1200507172',
 688                  'event' => '2',
 689                  'grade' => '0',
 690                  'raw_grade' => '0.75',
 691                  'penalty' => '0.1',
 692                  'id' => 862673,
 693              ),
 694              862716 => (object) array(
 695                  'attempt' => '23777',
 696                  'question' => '11135',
 697                  'originalquestion' => '0',
 698                  'seq_number' => '4',
 699                  'answer' => '1633-1633,1635-1635,1634-1635,1632-1632',
 700                  'timestamp' => '1200507467',
 701                  'event' => '2',
 702                  'grade' => '0',
 703                  'raw_grade' => '0.75',
 704                  'penalty' => '0.1',
 705                  'id' => 862716,
 706              ),
 707              862740 => (object) array(
 708                  'attempt' => '23777',
 709                  'question' => '11135',
 710                  'originalquestion' => '0',
 711                  'seq_number' => '5',
 712                  'answer' => '1633-1633,1635-1635,1634-1635,1632-1632',
 713                  'timestamp' => '1200507467',
 714                  'event' => '6',
 715                  'grade' => '0.75',
 716                  'raw_grade' => '0.75',
 717                  'penalty' => '0.1',
 718                  'id' => 862740,
 719              ),
 720          );
 721  
 722          $qa = $this->updater->convert_question_attempt($quiz, $attempt, $question, $qsession, $qstates);
 723  
 724          $expectedqa = (object) array(
 725              'behaviour' => 'deferredfeedback',
 726              'questionid' => 11135,
 727              'variant' => 1,
 728              'maxmark' => 1,
 729              'minfraction' => 0,
 730              'maxfraction' => 1,
 731              'flagged' => 0,
 732              'questionsummary' => 'Which of the following statements about subject gateways are true, and which are false? ' .
 733                      '{Subject gateways provide links to sites that have been quality checked; ' .
 734                      'Subject gateways offer more variety than search engines; ' .
 735                      'Subject gateways index websites automatically; ' .
 736                      'Subject gateways can provide a more direct route to websites containing academic content} ' .
 737                      '-> {True; False}',
 738              'rightanswer' => 'Subject gateways provide links to sites that have been quality checked -> True; ' .
 739                      'Subject gateways offer more variety than search engines -> False; ' .
 740                      'Subject gateways index websites automatically -> False; ' .
 741                      'Subject gateways can provide a more direct route to websites containing academic content -> True',
 742              'responsesummary' => 'Subject gateways offer more variety than search engines -> False; ' .
 743                      'Subject gateways can provide a more direct route to websites containing academic content -> True; ' .
 744                      'Subject gateways index websites automatically -> True; ' .
 745                      'Subject gateways provide links to sites that have been quality checked -> True',
 746              'timemodified' => 1200507467,
 747              'steps' => array(
 748                  0 => (object) array(
 749                      'sequencenumber' => 0,
 750                      'state' => 'todo',
 751                      'fraction' => null,
 752                      'timecreated' => 1200506648,
 753                      'userid' => 6584,
 754                      'data' => array('_stemorder' => '1633,1635,1634,1632',
 755                              '_choiceorder' => 'todo - see below'),
 756                  ),
 757                  1 => (object) array(
 758                      'sequencenumber' => 1,
 759                      'state' => 'complete',
 760                      'fraction' => null,
 761                      'timecreated' => 1200507025,
 762                      'userid' => 6584,
 763                      'data' => array('sub0' => 1633, 'sub1' => 1632, 'sub2' => 0, 'sub3' => 1632),
 764                  ),
 765                  2 => (object) array(
 766                      'sequencenumber' => 2,
 767                      'state' => 'complete',
 768                      'fraction' => null,
 769                      'timecreated' => 1200507125,
 770                      'userid' => 6584,
 771                      'data' => array('sub0' => 1633, 'sub1' => 1632, 'sub2' => 0, 'sub3' => 1632),
 772                  ),
 773                  3 => (object) array(
 774                      'sequencenumber' => 3,
 775                      'state' => 'complete',
 776                      'fraction' => null,
 777                      'timecreated' => 1200507172,
 778                      'userid' => 6584,
 779                      'data' => array('sub0' => 1633, 'sub1' => 1632, 'sub2' => 0, 'sub3' => 1632),
 780                  ),
 781                  4 => (object) array(
 782                      'sequencenumber' => 4,
 783                      'state' => 'complete',
 784                      'fraction' => null,
 785                      'timecreated' => 1200507467,
 786                      'userid' => 6584,
 787                      'data' => array('sub0' => 1633, 'sub1' => 1632, 'sub2' => 1632, 'sub3' => 1632),
 788                  ),
 789                  5 => (object) array(
 790                      'sequencenumber' => 5,
 791                      'state' => 'gradedpartial',
 792                      'fraction' => 0.75,
 793                      'timecreated' => 1200507467,
 794                      'userid' => 6584,
 795                      'data' => array('sub0' => 1633, 'sub1' => 1632, 'sub2' => 1632, 'sub3' => 1632, '-finish' => 1),
 796                  ),
 797              ),
 798          );
 799  
 800          // This is a random thing, so just set expected to actual.
 801          $expectedqa->steps[0]->data['_choiceorder'] = $qa->steps[0]->data['_choiceorder'];
 802          $order = explode(',', $qa->steps[0]->data['_choiceorder']);
 803          $order = array_combine(array_values($order), array_keys($order));
 804          for ($i = 1; $i <= 5; $i++) {
 805              for ($sub = 0; $sub < 5; $sub++) {
 806                  if (!array_key_exists('sub' . $sub, $expectedqa->steps[$i]->data) ||
 807                          $expectedqa->steps[$i]->data['sub' . $sub] == 0) {
 808                      continue;
 809                  }
 810                  $expectedqa->steps[$i]->data['sub' . $sub] =
 811                          $order[$expectedqa->steps[$i]->data['sub' . $sub]] + 1;
 812              }
 813          }
 814  
 815          $this->compare_qas($expectedqa, $qa);
 816      }
 817  }