Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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 Moodle XML format.
  19   *
  20   * @package    qformat_xml
  21   * @copyright  2010 The Open University
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace qformat_xml;
  26  
  27  use qformat_xml;
  28  use qtype_numerical_answer;
  29  use question_answer;
  30  use question_bank;
  31  use question_check_specified_fields_expectation;
  32  use question_hint;
  33  use question_hint_with_parts;
  34  
  35  defined('MOODLE_INTERNAL') || die();
  36  
  37  global $CFG;
  38  require_once($CFG->libdir . '/questionlib.php');
  39  require_once($CFG->dirroot . '/question/format/xml/format.php');
  40  require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
  41  
  42  /**
  43   * Unit tests for the matching question definition class.
  44   *
  45   * @package    qformat_xml
  46   * @copyright  2009 The Open University
  47   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  48   */
  49  class xmlformat_test extends \question_testcase {
  50      public function assert_same_xml($expectedxml, $xml) {
  51          $this->assertEquals(str_replace("\r\n", "\n", $expectedxml),
  52                  str_replace("\r\n", "\n", $xml));
  53      }
  54  
  55      public function make_test_question() {
  56          global $USER;
  57          $q = new \stdClass();
  58          $q->id = 0;
  59          $q->contextid = 0;
  60          $q->idnumber = null;
  61          $q->category = 0;
  62          $q->parent = 0;
  63          $q->questiontextformat = FORMAT_HTML;
  64          $q->generalfeedbackformat = FORMAT_HTML;
  65          $q->defaultmark = 1;
  66          $q->penalty = 0.3333333;
  67          $q->length = 1;
  68          $q->stamp = make_unique_id_code();
  69          $q->version = make_unique_id_code();
  70          $q->hidden = 0;
  71          $q->timecreated = time();
  72          $q->timemodified = time();
  73          $q->createdby = $USER->id;
  74          $q->modifiedby = $USER->id;
  75          return $q;
  76      }
  77  
  78      /**
  79       * The data the XML import format sends to save_question is not exactly
  80       * the same as the data returned from the editing form, so this method
  81       * makes necessary changes to the return value of
  82       * \test_question_maker::get_question_form_data so that the tests can work.
  83       * @param object $expectedq as returned by get_question_form_data.
  84       * @return object one more likely to match the return value of import_...().
  85       */
  86      public function remove_irrelevant_form_data_fields($expectedq) {
  87          return $this->itemid_to_files($expectedq);
  88      }
  89  
  90      /**
  91       * Becuase XML import uses a files array instead of an itemid integer to
  92       * handle saving files with a question, we need to covert the output of
  93       * \test_question_maker::get_question_form_data to match. This method recursively
  94       * replaces all array elements with key itemid with an array entry with
  95       * key files and value an empty array.
  96       *
  97       * @param mixed $var any data structure.
  98       * @return mixed an equivalent structure with the relacements made.
  99       */
 100      protected function itemid_to_files($var) {
 101          if (is_object($var)) {
 102              $newvar = new \stdClass();
 103              foreach (get_object_vars($var) as $field => $value) {
 104                  $newvar->$field = $this->itemid_to_files($value);
 105              }
 106  
 107          } else if (is_array($var)) {
 108              $newvar = array();
 109              foreach ($var as $index => $value) {
 110                  if ($index === 'itemid') {
 111                      $newvar['files'] = array();
 112                  } else {
 113                      $newvar[$index] = $this->itemid_to_files($value);
 114                  }
 115              }
 116  
 117          } else {
 118              $newvar = $var;
 119          }
 120  
 121          return $newvar;
 122      }
 123  
 124      public function test_xml_escape_simple_input_not_escaped() {
 125          $exporter = new qformat_xml();
 126          $string = 'Nothing funny here. Even if we go to a café or to 日本.';
 127          $this->assertEquals($string, $exporter->xml_escape($string));
 128      }
 129  
 130      public function test_xml_escape_html_wrapped_in_cdata() {
 131          $exporter = new qformat_xml();
 132          $string = '<p>Nothing <b>funny<b> here. Even if we go to a café or to 日本.</p>';
 133          $this->assertEquals('<![CDATA[' . $string . ']]>', $exporter->xml_escape($string));
 134      }
 135  
 136      public function test_xml_escape_script_tag_handled_ok() {
 137          $exporter = new qformat_xml();
 138          $input = '<script><![CDATA[alert(1<2);]]></script>';
 139          $expected = '<![CDATA[<script><![CDATA[alert(1<2);]]]]><![CDATA[></script>]]>';
 140          $this->assertEquals($expected, $exporter->xml_escape($input));
 141  
 142          // Check that parsing the expected result does give the input again.
 143          $parsed = simplexml_load_string('<div>' . $expected . '</div>');
 144          $this->assertEquals($input, $parsed->xpath('//div')[0]);
 145      }
 146  
 147      public function test_xml_escape_code_that_looks_like_cdata_end_ok() {
 148          $exporter = new qformat_xml();
 149          $input = "if (x[[0]]>a) print('hah');";
 150          $expected = "<![CDATA[if (x[[0]]]]><![CDATA[>a) print('hah');]]>";
 151          $this->assertEquals($expected, $exporter->xml_escape($input));
 152  
 153          // Check that parsing the expected result does give the input again.
 154          $parsed = simplexml_load_string('<div>' . $expected . '</div>');
 155          $this->assertEquals($input, $parsed->xpath('//div')[0]);
 156      }
 157  
 158      public function test_write_hint_basic() {
 159          $q = $this->make_test_question();
 160          $q->contextid = \context_system::instance()->id;
 161          $q->name = 'Short answer question';
 162          $q->questiontext = 'Name an amphibian: __________';
 163          $q->generalfeedback = 'Generalfeedback: frog or toad would have been OK.';
 164          if (!isset($q->options)) {
 165              $q->options = new \stdClass();
 166          }
 167          $q->options->usecase = false;
 168          $q->options->answers = array(
 169              13 => new question_answer(13, 'frog', 1.0, 'Frog is a very good answer.', FORMAT_HTML),
 170              14 => new question_answer(14, 'toad', 0.8, 'Toad is an OK good answer.', FORMAT_HTML),
 171              15 => new question_answer(15, '*', 0.0, 'That is a bad answer.', FORMAT_HTML),
 172          );
 173          $q->qtype = 'shortanswer';
 174          $q->hints = array(
 175              new question_hint(0, 'This is the first hint.', FORMAT_MOODLE),
 176          );
 177  
 178          $exporter = new qformat_xml();
 179          $xml = $exporter->writequestion($q);
 180  
 181          $this->assertMatchesRegularExpression('|<hint format=\"moodle_auto_format\">\s*<text>\s*' .
 182                  'This is the first hint\.\s*</text>\s*</hint>|', $xml);
 183          $this->assertDoesNotMatchRegularExpression('|<shownumcorrect/>|', $xml);
 184          $this->assertDoesNotMatchRegularExpression('|<clearwrong/>|', $xml);
 185          $this->assertDoesNotMatchRegularExpression('|<options>|', $xml);
 186      }
 187  
 188      public function test_write_hint_with_parts() {
 189          $q = $this->make_test_question();
 190          $q->contextid = \context_system::instance()->id;
 191          $q->name = 'Matching question';
 192          $q->questiontext = 'Classify the animals.';
 193          $q->generalfeedback = 'Frogs and toads are amphibians, the others are mammals.';
 194          $q->qtype = 'match';
 195  
 196          if (!isset($q->options)) {
 197              $q->options = new \stdClass();
 198          }
 199          $q->options->shuffleanswers = 1;
 200          $q->options->correctfeedback = '';
 201          $q->options->correctfeedbackformat = FORMAT_HTML;
 202          $q->options->partiallycorrectfeedback = '';
 203          $q->options->partiallycorrectfeedbackformat = FORMAT_HTML;
 204          $q->options->incorrectfeedback = '';
 205          $q->options->incorrectfeedbackformat = FORMAT_HTML;
 206  
 207          $q->options->subquestions = array();
 208          $q->hints = array(
 209              new question_hint_with_parts(0, 'This is the first hint.', FORMAT_HTML, false, true),
 210              new question_hint_with_parts(0, 'This is the second hint.', FORMAT_HTML, true, false),
 211          );
 212  
 213          $exporter = new qformat_xml();
 214          $xml = $exporter->writequestion($q);
 215  
 216          $this->assertMatchesRegularExpression(
 217                  '|<hint format=\"html\">\s*<text>\s*This is the first hint\.\s*</text>|', $xml);
 218          $this->assertMatchesRegularExpression(
 219                  '|<hint format=\"html\">\s*<text>\s*This is the second hint\.\s*</text>|', $xml);
 220          list($ignored, $hint1, $hint2) = explode('<hint', $xml);
 221          $this->assertDoesNotMatchRegularExpression('|<shownumcorrect/>|', $hint1);
 222          $this->assertMatchesRegularExpression('|<clearwrong/>|', $hint1);
 223          $this->assertMatchesRegularExpression('|<shownumcorrect/>|', $hint2);
 224          $this->assertDoesNotMatchRegularExpression('|<clearwrong/>|', $hint2);
 225          $this->assertDoesNotMatchRegularExpression('|<options>|', $xml);
 226      }
 227  
 228      public function test_import_hints_no_parts() {
 229          $xml = <<<END
 230  <question>
 231      <hint>
 232          <text>This is the first hint</text>
 233          <clearwrong/>
 234      </hint>
 235      <hint>
 236          <text>This is the second hint</text>
 237          <shownumcorrect/>
 238      </hint>
 239  </question>
 240  END;
 241  
 242          $questionxml = xmlize($xml);
 243          $qo = new \stdClass();
 244  
 245          $importer = new qformat_xml();
 246          $importer->import_hints($qo, $questionxml['question'], false, false, 'html');
 247  
 248          $this->assertEquals(array(
 249                  array('text' => 'This is the first hint',
 250                          'format' => FORMAT_HTML),
 251                  array('text' => 'This is the second hint',
 252                          'format' => FORMAT_HTML),
 253                  ), $qo->hint);
 254          $this->assertFalse(isset($qo->hintclearwrong));
 255          $this->assertFalse(isset($qo->hintshownumcorrect));
 256      }
 257  
 258      public function test_import_hints_with_parts() {
 259          $xml = <<<END
 260  <question>
 261      <hint>
 262          <text>This is the first hint</text>
 263          <clearwrong/>
 264      </hint>
 265      <hint>
 266          <text>This is the second hint</text>
 267          <shownumcorrect/>
 268      </hint>
 269  </question>
 270  END;
 271  
 272          $questionxml = xmlize($xml);
 273          $qo = new \stdClass();
 274  
 275          $importer = new qformat_xml();
 276          $importer->import_hints($qo, $questionxml['question'], true, true, 'html');
 277  
 278          $this->assertEquals(array(
 279                  array('text' => 'This is the first hint',
 280                          'format' => FORMAT_HTML),
 281                  array('text' => 'This is the second hint',
 282                          'format' => FORMAT_HTML),
 283                  ), $qo->hint);
 284          $this->assertEquals(array(1, 0), $qo->hintclearwrong);
 285          $this->assertEquals(array(0, 1), $qo->hintshownumcorrect);
 286      }
 287  
 288      public function test_import_no_hints_no_error() {
 289          $xml = <<<END
 290  <question>
 291  </question>
 292  END;
 293  
 294          $questionxml = xmlize($xml);
 295          $qo = new \stdClass();
 296  
 297          $importer = new qformat_xml();
 298          $importer->import_hints($qo, $questionxml['question'], 'html');
 299  
 300          $this->assertFalse(isset($qo->hint));
 301      }
 302  
 303      public function test_import_description() {
 304          $xml = '  <question type="description">
 305      <name>
 306        <text>A description</text>
 307      </name>
 308      <questiontext format="html">
 309        <text>The question text.</text>
 310      </questiontext>
 311      <generalfeedback>
 312        <text>Here is some general feedback.</text>
 313      </generalfeedback>
 314      <defaultgrade>0</defaultgrade>
 315      <penalty>0</penalty>
 316      <hidden>0</hidden>
 317      <tags>
 318        <tag><text>tagDescription</text></tag>
 319        <tag><text>tagTest</text></tag>
 320      </tags>
 321    </question>';
 322          $xmldata = xmlize($xml);
 323  
 324          $importer = new qformat_xml();
 325          $q = $importer->import_description($xmldata['question']);
 326  
 327          $expectedq = new \stdClass();
 328          $expectedq->qtype = 'description';
 329          $expectedq->name = 'A description';
 330          $expectedq->questiontext = 'The question text.';
 331          $expectedq->questiontextformat = FORMAT_HTML;
 332          $expectedq->generalfeedback = 'Here is some general feedback.';
 333          $expectedq->defaultmark = 0;
 334          $expectedq->length = 0;
 335          $expectedq->penalty = 0;
 336          $expectedq->tags = array('tagDescription', 'tagTest');
 337  
 338          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 339      }
 340  
 341      public function test_export_description() {
 342          $qdata = new \stdClass();
 343          $qdata->id = 123;
 344          $qdata->contextid = \context_system::instance()->id;
 345          $qdata->qtype = 'description';
 346          $qdata->name = 'A description';
 347          $qdata->questiontext = 'The question text.';
 348          $qdata->questiontextformat = FORMAT_HTML;
 349          $qdata->generalfeedback = 'Here is some general feedback.';
 350          $qdata->generalfeedbackformat = FORMAT_HTML;
 351          $qdata->defaultmark = 0;
 352          $qdata->length = 0;
 353          $qdata->penalty = 0;
 354          $qdata->hidden = 0;
 355          $qdata->idnumber = null;
 356  
 357          $exporter = new qformat_xml();
 358          $xml = $exporter->writequestion($qdata);
 359  
 360          $expectedxml = '<!-- question: 123  -->
 361    <question type="description">
 362      <name>
 363        <text>A description</text>
 364      </name>
 365      <questiontext format="html">
 366        <text>The question text.</text>
 367      </questiontext>
 368      <generalfeedback format="html">
 369        <text>Here is some general feedback.</text>
 370      </generalfeedback>
 371      <defaultgrade>0</defaultgrade>
 372      <penalty>0</penalty>
 373      <hidden>0</hidden>
 374      <idnumber></idnumber>
 375    </question>
 376  ';
 377  
 378          $this->assert_same_xml($expectedxml, $xml);
 379      }
 380  
 381      public function test_import_essay_20() {
 382          $xml = '  <question type="essay">
 383      <name>
 384        <text>An essay</text>
 385      </name>
 386      <questiontext format="moodle_auto_format">
 387        <text>Write something.</text>
 388      </questiontext>
 389      <generalfeedback>
 390        <text>I hope you wrote something interesting.</text>
 391      </generalfeedback>
 392      <defaultgrade>1</defaultgrade>
 393      <penalty>0</penalty>
 394      <hidden>0</hidden>
 395      <tags>
 396        <tag><text>tagEssay</text></tag>
 397        <tag><text>tagEssay20</text></tag>
 398        <tag><text>tagTest</text></tag>
 399      </tags>
 400    </question>';
 401          $xmldata = xmlize($xml);
 402  
 403          $importer = new qformat_xml();
 404          $q = $importer->import_essay($xmldata['question']);
 405  
 406          $expectedq = new \stdClass();
 407          $expectedq->qtype = 'essay';
 408          $expectedq->name = 'An essay';
 409          $expectedq->questiontext = 'Write something.';
 410          $expectedq->questiontextformat = FORMAT_MOODLE;
 411          $expectedq->generalfeedback = 'I hope you wrote something interesting.';
 412          $expectedq->defaultmark = 1;
 413          $expectedq->length = 1;
 414          $expectedq->penalty = 0;
 415          $expectedq->responseformat = 'editor';
 416          $expectedq->responserequired = 1;
 417          $expectedq->responsefieldlines = 15;
 418          $expectedq->minwordlimit = null;
 419          $expectedq->minwordenabled = false;
 420          $expectedq->maxwordlimit = null;
 421          $expectedq->maxwordenabled = false;
 422          $expectedq->attachments = 0;
 423          $expectedq->attachmentsrequired = 0;
 424          $expectedq->maxbytes = 0;
 425          $expectedq->filetypeslist = null;
 426          $expectedq->graderinfo['text'] = '';
 427          $expectedq->graderinfo['format'] = FORMAT_MOODLE;
 428          $expectedq->responsetemplate['text'] = '';
 429          $expectedq->responsetemplate['format'] = FORMAT_MOODLE;
 430          $expectedq->tags = array('tagEssay', 'tagEssay20', 'tagTest');
 431  
 432          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 433      }
 434  
 435      public function test_import_essay_21() {
 436          $xml = '  <question type="essay">
 437      <name>
 438        <text>An essay</text>
 439      </name>
 440      <questiontext format="moodle_auto_format">
 441        <text>Write something.</text>
 442      </questiontext>
 443      <generalfeedback>
 444        <text>I hope you wrote something interesting.</text>
 445      </generalfeedback>
 446      <defaultgrade>1</defaultgrade>
 447      <penalty>0</penalty>
 448      <hidden>0</hidden>
 449      <responseformat>monospaced</responseformat>
 450      <responserequired>0</responserequired>
 451      <responsefieldlines>42</responsefieldlines>
 452      <attachments>-1</attachments>
 453      <attachmentsrequired>1</attachmentsrequired>
 454      <graderinfo format="html">
 455          <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text>
 456      </graderinfo>
 457      <responsetemplate format="html">
 458          <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text>
 459      </responsetemplate>
 460      <tags>
 461        <tag><text>tagEssay</text></tag>
 462        <tag><text>tagEssay21</text></tag>
 463        <tag><text>tagTest</text></tag>
 464      </tags>
 465    </question>';
 466          $xmldata = xmlize($xml);
 467  
 468          $importer = new qformat_xml();
 469          $q = $importer->import_essay($xmldata['question']);
 470  
 471          $expectedq = new \stdClass();
 472          $expectedq->qtype = 'essay';
 473          $expectedq->name = 'An essay';
 474          $expectedq->questiontext = 'Write something.';
 475          $expectedq->questiontextformat = FORMAT_MOODLE;
 476          $expectedq->generalfeedback = 'I hope you wrote something interesting.';
 477          $expectedq->defaultmark = 1;
 478          $expectedq->length = 1;
 479          $expectedq->penalty = 0;
 480          $expectedq->responseformat = 'monospaced';
 481          $expectedq->responserequired = 0;
 482          $expectedq->responsefieldlines = 42;
 483          $expectedq->minwordlimit = null;
 484          $expectedq->minwordenabled = false;
 485          $expectedq->maxwordlimit = null;
 486          $expectedq->maxwordenabled = false;
 487          $expectedq->attachments = -1;
 488          $expectedq->attachmentsrequired = 1;
 489          $expectedq->maxbytes = 0;
 490          $expectedq->filetypeslist = null;
 491          $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>';
 492          $expectedq->graderinfo['format'] = FORMAT_HTML;
 493          $expectedq->responsetemplate['text'] = '<p>Here is something <b>really</b> interesting.</p>';
 494          $expectedq->responsetemplate['format'] = FORMAT_HTML;
 495          $expectedq->tags = array('tagEssay', 'tagEssay21', 'tagTest');
 496  
 497          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 498      }
 499  
 500      public function test_import_essay_311() {
 501          $xml = '  <question type="essay">
 502      <name>
 503        <text>An essay</text>
 504      </name>
 505      <questiontext format="moodle_auto_format">
 506        <text>Write something.</text>
 507      </questiontext>
 508      <generalfeedback>
 509        <text>I hope you wrote something interesting.</text>
 510      </generalfeedback>
 511      <defaultgrade>1</defaultgrade>
 512      <penalty>0</penalty>
 513      <hidden>0</hidden>
 514      <responseformat>monospaced</responseformat>
 515      <responserequired>0</responserequired>
 516      <responsefieldlines>42</responsefieldlines>
 517      <minwordlimit>10</minwordlimit>
 518      <maxwordlimit>20</maxwordlimit>
 519      <attachments>-1</attachments>
 520      <attachmentsrequired>1</attachmentsrequired>
 521      <maxbytes>52428800</maxbytes>
 522      <filetypeslist>.pdf,.zip.,.docx</filetypeslist>
 523      <graderinfo format="html">
 524          <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text>
 525      </graderinfo>
 526      <responsetemplate format="html">
 527          <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text>
 528      </responsetemplate>
 529      <tags>
 530        <tag><text>tagEssay</text></tag>
 531        <tag><text>tagEssay21</text></tag>
 532        <tag><text>tagTest</text></tag>
 533      </tags>
 534    </question>';
 535          $xmldata = xmlize($xml);
 536  
 537          $importer = new qformat_xml();
 538          $q = $importer->import_essay($xmldata['question']);
 539  
 540          $expectedq = new \stdClass();
 541          $expectedq->qtype = 'essay';
 542          $expectedq->name = 'An essay';
 543          $expectedq->questiontext = 'Write something.';
 544          $expectedq->questiontextformat = FORMAT_MOODLE;
 545          $expectedq->generalfeedback = 'I hope you wrote something interesting.';
 546          $expectedq->defaultmark = 1;
 547          $expectedq->length = 1;
 548          $expectedq->penalty = 0;
 549          $expectedq->responseformat = 'monospaced';
 550          $expectedq->responserequired = 0;
 551          $expectedq->responsefieldlines = 42;
 552          $expectedq->minwordlimit = 10;
 553          $expectedq->minwordenabled = true;
 554          $expectedq->maxwordlimit = 20;
 555          $expectedq->maxwordenabled = true;
 556          $expectedq->attachments = -1;
 557          $expectedq->attachmentsrequired = 1;
 558          $expectedq->maxbytes = 52428800; // 50MB.
 559          $expectedq->filetypeslist = '.pdf,.zip.,.docx';
 560          $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>';
 561          $expectedq->graderinfo['format'] = FORMAT_HTML;
 562          $expectedq->responsetemplate['text'] = '<p>Here is something <b>really</b> interesting.</p>';
 563          $expectedq->responsetemplate['format'] = FORMAT_HTML;
 564          $expectedq->tags = array('tagEssay', 'tagEssay21', 'tagTest');
 565  
 566          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 567      }
 568  
 569      public function test_export_essay() {
 570          $qdata = new \stdClass();
 571          $qdata->id = 123;
 572          $qdata->contextid = \context_system::instance()->id;
 573          $qdata->qtype = 'essay';
 574          $qdata->name = 'An essay';
 575          $qdata->questiontext = 'Write something.';
 576          $qdata->questiontextformat = FORMAT_MOODLE;
 577          $qdata->generalfeedback = 'I hope you wrote something interesting.';
 578          $qdata->generalfeedbackformat = FORMAT_MOODLE;
 579          $qdata->defaultmark = 1;
 580          $qdata->length = 1;
 581          $qdata->penalty = 0;
 582          $qdata->hidden = 0;
 583          $qdata->idnumber = null;
 584          $qdata->options = new \stdClass();
 585          $qdata->options->id = 456;
 586          $qdata->options->questionid = 123;
 587          $qdata->options->responseformat = 'monospaced';
 588          $qdata->options->responserequired = 0;
 589          $qdata->options->responsefieldlines = 42;
 590          $qdata->options->minwordlimit = 10;
 591          $qdata->options->maxwordlimit = 20;
 592          $qdata->options->attachments = -1;
 593          $qdata->options->attachmentsrequired = 1;
 594          $qdata->options->graderinfo = '<p>Grade <b>generously</b>!</p>';
 595          $qdata->options->graderinfoformat = FORMAT_HTML;
 596          $qdata->options->responsetemplate = '<p>Here is something <b>really</b> interesting.</p>';
 597          $qdata->options->responsetemplateformat = FORMAT_HTML;
 598          $qdata->options->maxbytes = 52428800; // 50MB.
 599          $qdata->options->filetypeslist = '.pdf,.zip.,.docx';
 600          $exporter = new qformat_xml();
 601          $xml = $exporter->writequestion($qdata);
 602  
 603          $expectedxml = '<!-- question: 123  -->
 604    <question type="essay">
 605      <name>
 606        <text>An essay</text>
 607      </name>
 608      <questiontext format="moodle_auto_format">
 609        <text>Write something.</text>
 610      </questiontext>
 611      <generalfeedback format="moodle_auto_format">
 612        <text>I hope you wrote something interesting.</text>
 613      </generalfeedback>
 614      <defaultgrade>1</defaultgrade>
 615      <penalty>0</penalty>
 616      <hidden>0</hidden>
 617      <idnumber></idnumber>
 618      <responseformat>monospaced</responseformat>
 619      <responserequired>0</responserequired>
 620      <responsefieldlines>42</responsefieldlines>
 621      <minwordlimit>10</minwordlimit>
 622      <maxwordlimit>20</maxwordlimit>
 623      <attachments>-1</attachments>
 624      <attachmentsrequired>1</attachmentsrequired>
 625      <maxbytes>52428800</maxbytes>
 626      <filetypeslist>.pdf,.zip.,.docx</filetypeslist>
 627      <graderinfo format="html">
 628        <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text>
 629      </graderinfo>
 630      <responsetemplate format="html">
 631        <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text>
 632      </responsetemplate>
 633    </question>
 634  ';
 635  
 636          $this->assert_same_xml($expectedxml, $xml);
 637      }
 638  
 639      public function test_import_match_19() {
 640          $xml = '  <question type="matching">
 641      <name>
 642        <text>Matching question</text>
 643      </name>
 644      <questiontext format="html">
 645        <text>Match the upper and lower case letters.</text>
 646      </questiontext>
 647      <generalfeedback>
 648        <text>The answer is A -> a, B -> b and C -> c.</text>
 649      </generalfeedback>
 650      <defaultgrade>1</defaultgrade>
 651      <penalty>0.3333333</penalty>
 652      <hidden>0</hidden>
 653      <shuffleanswers>false</shuffleanswers>
 654      <correctfeedback>
 655        <text>Well done.</text>
 656      </correctfeedback>
 657      <partiallycorrectfeedback>
 658        <text>Not entirely.</text>
 659      </partiallycorrectfeedback>
 660      <incorrectfeedback>
 661        <text>Completely wrong!</text>
 662      </incorrectfeedback>
 663      <subquestion>
 664        <text>A</text>
 665        <answer>
 666          <text>a</text>
 667        </answer>
 668      </subquestion>
 669      <subquestion>
 670        <text>B</text>
 671        <answer>
 672          <text>b</text>
 673        </answer>
 674      </subquestion>
 675      <subquestion>
 676        <text>C</text>
 677        <answer>
 678          <text>c</text>
 679        </answer>
 680      </subquestion>
 681      <subquestion>
 682        <text></text>
 683        <answer>
 684          <text>d</text>
 685        </answer>
 686      </subquestion>
 687      <hint>
 688        <text>Hint 1</text>
 689        <shownumcorrect />
 690      </hint>
 691      <hint>
 692        <text></text>
 693        <shownumcorrect />
 694        <clearwrong />
 695      </hint>
 696      <tags>
 697        <tag><text>tagMatching</text></tag>
 698        <tag><text>tagTest</text></tag>
 699      </tags>
 700    </question>';
 701          $xmldata = xmlize($xml);
 702  
 703          $importer = new qformat_xml();
 704          $q = $importer->import_match($xmldata['question']);
 705  
 706          $expectedq = new \stdClass();
 707          $expectedq->qtype = 'match';
 708          $expectedq->name = 'Matching question';
 709          $expectedq->questiontext = 'Match the upper and lower case letters.';
 710          $expectedq->questiontextformat = FORMAT_HTML;
 711          $expectedq->correctfeedback = array('text' => 'Well done.',
 712                  'format' => FORMAT_HTML);
 713          $expectedq->partiallycorrectfeedback = array('text' => 'Not entirely.',
 714                  'format' => FORMAT_HTML);
 715          $expectedq->shownumcorrect = false;
 716          $expectedq->incorrectfeedback = array('text' => 'Completely wrong!',
 717                  'format' => FORMAT_HTML);
 718          $expectedq->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
 719          $expectedq->generalfeedbackformat = FORMAT_HTML;
 720          $expectedq->defaultmark = 1;
 721          $expectedq->length = 1;
 722          $expectedq->penalty = 0.3333333;
 723          $expectedq->shuffleanswers = 0;
 724          $expectedq->subquestions = array(
 725              array('text' => 'A', 'format' => FORMAT_HTML),
 726              array('text' => 'B', 'format' => FORMAT_HTML),
 727              array('text' => 'C', 'format' => FORMAT_HTML),
 728              array('text' => '', 'format' => FORMAT_HTML));
 729          $expectedq->subanswers = array('a', 'b', 'c', 'd');
 730          $expectedq->hint = array(
 731              array('text' => 'Hint 1', 'format' => FORMAT_HTML),
 732              array('text' => '', 'format' => FORMAT_HTML),
 733          );
 734          $expectedq->hintshownumcorrect = array(true, true);
 735          $expectedq->hintclearwrong = array(false, true);
 736          $expectedq->tags = array('tagMatching', 'tagTest');
 737  
 738          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 739      }
 740  
 741      public function test_export_match() {
 742          $qdata = new \stdClass();
 743          $qdata->id = 123;
 744          $qdata->contextid = \context_system::instance()->id;
 745          $qdata->qtype = 'match';
 746          $qdata->name = 'Matching question';
 747          $qdata->questiontext = 'Match the upper and lower case letters.';
 748          $qdata->questiontextformat = FORMAT_HTML;
 749          $qdata->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
 750          $qdata->generalfeedbackformat = FORMAT_HTML;
 751          $qdata->defaultmark = 1;
 752          $qdata->length = 1;
 753          $qdata->penalty = 0.3333333;
 754          $qdata->hidden = 0;
 755          $qdata->idnumber = null;
 756  
 757          $qdata->options = new \stdClass();
 758          $qdata->options->shuffleanswers = 1;
 759          $qdata->options->correctfeedback = 'Well done.';
 760          $qdata->options->correctfeedbackformat = FORMAT_HTML;
 761          $qdata->options->partiallycorrectfeedback = 'Not entirely.';
 762          $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML;
 763          $qdata->options->shownumcorrect = false;
 764          $qdata->options->incorrectfeedback = 'Completely wrong!';
 765          $qdata->options->incorrectfeedbackformat = FORMAT_HTML;
 766  
 767          $subq1 = new \stdClass();
 768          $subq1->id = -4;
 769          $subq1->questiontext = 'A';
 770          $subq1->questiontextformat = FORMAT_HTML;
 771          $subq1->answertext = 'a';
 772  
 773          $subq2 = new \stdClass();
 774          $subq2->id = -3;
 775          $subq2->questiontext = 'B';
 776          $subq2->questiontextformat = FORMAT_HTML;
 777          $subq2->answertext = 'b';
 778  
 779          $subq3 = new \stdClass();
 780          $subq3->id = -2;
 781          $subq3->questiontext = 'C';
 782          $subq3->questiontextformat = FORMAT_HTML;
 783          $subq3->answertext = 'c';
 784  
 785          $subq4 = new \stdClass();
 786          $subq4->id = -1;
 787          $subq4->questiontext = '';
 788          $subq4->questiontextformat = FORMAT_HTML;
 789          $subq4->answertext = 'd';
 790  
 791          $qdata->options->subquestions = array(
 792                  $subq1, $subq2, $subq3, $subq4);
 793  
 794          $qdata->hints = array(
 795              new question_hint_with_parts(0, 'Hint 1', FORMAT_HTML, true, false),
 796              new question_hint_with_parts(0, '', FORMAT_HTML, true, true),
 797          );
 798  
 799          $exporter = new qformat_xml();
 800          $xml = $exporter->writequestion($qdata);
 801  
 802          $expectedxml = '<!-- question: 123  -->
 803    <question type="matching">
 804      <name>
 805        <text>Matching question</text>
 806      </name>
 807      <questiontext format="html">
 808        <text>Match the upper and lower case letters.</text>
 809      </questiontext>
 810      <generalfeedback format="html">
 811        <text><![CDATA[The answer is A -> a, B -> b and C -> c.]]></text>
 812      </generalfeedback>
 813      <defaultgrade>1</defaultgrade>
 814      <penalty>0.3333333</penalty>
 815      <hidden>0</hidden>
 816      <idnumber></idnumber>
 817      <shuffleanswers>true</shuffleanswers>
 818      <correctfeedback format="html">
 819        <text>Well done.</text>
 820      </correctfeedback>
 821      <partiallycorrectfeedback format="html">
 822        <text>Not entirely.</text>
 823      </partiallycorrectfeedback>
 824      <incorrectfeedback format="html">
 825        <text>Completely wrong!</text>
 826      </incorrectfeedback>
 827      <subquestion format="html">
 828        <text>A</text>
 829        <answer>
 830          <text>a</text>
 831        </answer>
 832      </subquestion>
 833      <subquestion format="html">
 834        <text>B</text>
 835        <answer>
 836          <text>b</text>
 837        </answer>
 838      </subquestion>
 839      <subquestion format="html">
 840        <text>C</text>
 841        <answer>
 842          <text>c</text>
 843        </answer>
 844      </subquestion>
 845      <subquestion format="html">
 846        <text></text>
 847        <answer>
 848          <text>d</text>
 849        </answer>
 850      </subquestion>
 851      <hint format="html">
 852        <text>Hint 1</text>
 853        <shownumcorrect/>
 854      </hint>
 855      <hint format="html">
 856        <text></text>
 857        <shownumcorrect/>
 858        <clearwrong/>
 859      </hint>
 860    </question>
 861  ';
 862  
 863          $this->assert_same_xml($expectedxml, $xml);
 864      }
 865  
 866      public function test_import_multichoice_19() {
 867          $xml = '  <question type="multichoice">
 868      <name>
 869        <text>Multiple choice question</text>
 870      </name>
 871      <questiontext format="html">
 872        <text>Which are the even numbers?</text>
 873      </questiontext>
 874      <generalfeedback>
 875        <text>The even numbers are 2 and 4.</text>
 876      </generalfeedback>
 877      <defaultgrade>2</defaultgrade>
 878      <penalty>0.3333333</penalty>
 879      <hidden>0</hidden>
 880      <single>false</single>
 881      <shuffleanswers>false</shuffleanswers>
 882      <answernumbering>abc</answernumbering>
 883      <correctfeedback>
 884        <text><![CDATA[<p>Your answer is correct.</p>]]></text>
 885      </correctfeedback>
 886      <partiallycorrectfeedback>
 887        <text><![CDATA[<p>Your answer is partially correct.</p>]]></text>
 888      </partiallycorrectfeedback>
 889      <incorrectfeedback>
 890        <text><![CDATA[<p>Your answer is incorrect.</p>]]></text>
 891      </incorrectfeedback>
 892      <shownumcorrect/>
 893      <answer fraction="0">
 894        <text>1</text>
 895        <feedback>
 896          <text></text>
 897        </feedback>
 898      </answer>
 899      <answer fraction="100">
 900        <text>2</text>
 901        <feedback>
 902          <text></text>
 903        </feedback>
 904      </answer>
 905      <answer fraction="0">
 906        <text>3</text>
 907        <feedback>
 908          <text></text>
 909        </feedback>
 910      </answer>
 911      <answer fraction="100">
 912        <text>4</text>
 913        <feedback>
 914          <text></text>
 915        </feedback>
 916      </answer>
 917      <hint>
 918        <text>Hint 1.</text>
 919      </hint>
 920      <hint>
 921        <text>Hint 2.</text>
 922      </hint>
 923    </question>';
 924          $xmldata = xmlize($xml);
 925  
 926          $importer = new qformat_xml();
 927          $q = $importer->import_multichoice($xmldata['question']);
 928  
 929          $expectedq = new \stdClass();
 930          $expectedq->qtype = 'multichoice';
 931          $expectedq->name = 'Multiple choice question';
 932          $expectedq->questiontext = 'Which are the even numbers?';
 933          $expectedq->questiontextformat = FORMAT_HTML;
 934          $expectedq->correctfeedback = array(
 935                  'text'   => '<p>Your answer is correct.</p>',
 936                  'format' => FORMAT_HTML);
 937          $expectedq->shownumcorrect = false;
 938          $expectedq->partiallycorrectfeedback = array(
 939                  'text'   => '<p>Your answer is partially correct.</p>',
 940                  'format' => FORMAT_HTML);
 941          $expectedq->shownumcorrect = true;
 942          $expectedq->incorrectfeedback = array(
 943                  'text'   => '<p>Your answer is incorrect.</p>',
 944                  'format' => FORMAT_HTML);
 945          $expectedq->generalfeedback = 'The even numbers are 2 and 4.';
 946          $expectedq->defaultmark = 2;
 947          $expectedq->length = 1;
 948          $expectedq->penalty = 0.3333333;
 949          $expectedq->shuffleanswers = 0;
 950          $expectedq->single = false;
 951  
 952          $expectedq->answer = array(
 953              array('text' => '1', 'format' => FORMAT_HTML),
 954              array('text' => '2', 'format' => FORMAT_HTML),
 955              array('text' => '3', 'format' => FORMAT_HTML),
 956              array('text' => '4', 'format' => FORMAT_HTML));
 957          $expectedq->fraction = array(0, 1, 0, 1);
 958          $expectedq->feedback = array(
 959              array('text' => '', 'format' => FORMAT_HTML),
 960              array('text' => '', 'format' => FORMAT_HTML),
 961              array('text' => '', 'format' => FORMAT_HTML),
 962              array('text' => '', 'format' => FORMAT_HTML));
 963  
 964          $expectedq->hint = array(
 965              array('text' => 'Hint 1.', 'format' => FORMAT_HTML),
 966              array('text' => 'Hint 2.', 'format' => FORMAT_HTML),
 967          );
 968          $expectedq->hintshownumcorrect = array(false, false);
 969          $expectedq->hintclearwrong = array(false, false);
 970  
 971          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
 972      }
 973  
 974      public function test_export_multichoice() {
 975          $qdata = new \stdClass();
 976          $qdata->id = 123;
 977          $qdata->contextid = \context_system::instance()->id;
 978          $qdata->qtype = 'multichoice';
 979          $qdata->name = 'Multiple choice question';
 980          $qdata->questiontext = 'Which are the even numbers?';
 981          $qdata->questiontextformat = FORMAT_HTML;
 982          $qdata->generalfeedback = 'The even numbers are 2 and 4.';
 983          $qdata->generalfeedbackformat = FORMAT_HTML;
 984          $qdata->defaultmark = 2;
 985          $qdata->length = 1;
 986          $qdata->penalty = 0.3333333;
 987          $qdata->hidden = 0;
 988          $qdata->idnumber = null;
 989  
 990          $qdata->options = new \stdClass();
 991          $qdata->options->single = 0;
 992          $qdata->options->shuffleanswers = 0;
 993          $qdata->options->answernumbering = 'abc';
 994          $qdata->options->showstandardinstruction = 0;
 995          $qdata->options->correctfeedback = '<p>Your answer is correct.</p>';
 996          $qdata->options->correctfeedbackformat = FORMAT_HTML;
 997          $qdata->options->partiallycorrectfeedback = '<p>Your answer is partially correct.</p>';
 998          $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML;
 999          $qdata->options->shownumcorrect = 1;
1000          $qdata->options->incorrectfeedback = '<p>Your answer is incorrect.</p>';
1001          $qdata->options->incorrectfeedbackformat = FORMAT_HTML;
1002  
1003          $qdata->options->answers = array(
1004              13 => new question_answer(13, '1', 0, '', FORMAT_HTML),
1005              14 => new question_answer(14, '2', 1, '', FORMAT_HTML),
1006              15 => new question_answer(15, '3', 0, '', FORMAT_HTML),
1007              16 => new question_answer(16, '4', 1, '', FORMAT_HTML),
1008          );
1009  
1010          $qdata->hints = array(
1011              new question_hint_with_parts(0, 'Hint 1.', FORMAT_HTML, false, false),
1012              new question_hint_with_parts(0, 'Hint 2.', FORMAT_HTML, false, false),
1013          );
1014  
1015          $exporter = new qformat_xml();
1016          $xml = $exporter->writequestion($qdata);
1017  
1018          $expectedxml = '<!-- question: 123  -->
1019    <question type="multichoice">
1020      <name>
1021        <text>Multiple choice question</text>
1022      </name>
1023      <questiontext format="html">
1024        <text>Which are the even numbers?</text>
1025      </questiontext>
1026      <generalfeedback format="html">
1027        <text>The even numbers are 2 and 4.</text>
1028      </generalfeedback>
1029      <defaultgrade>2</defaultgrade>
1030      <penalty>0.3333333</penalty>
1031      <hidden>0</hidden>
1032      <idnumber></idnumber>
1033      <single>false</single>
1034      <shuffleanswers>false</shuffleanswers>
1035      <answernumbering>abc</answernumbering>
1036      <showstandardinstruction>0</showstandardinstruction>
1037      <correctfeedback format="html">
1038        <text><![CDATA[<p>Your answer is correct.</p>]]></text>
1039      </correctfeedback>
1040      <partiallycorrectfeedback format="html">
1041        <text><![CDATA[<p>Your answer is partially correct.</p>]]></text>
1042      </partiallycorrectfeedback>
1043      <incorrectfeedback format="html">
1044        <text><![CDATA[<p>Your answer is incorrect.</p>]]></text>
1045      </incorrectfeedback>
1046      <shownumcorrect/>
1047      <answer fraction="0" format="plain_text">
1048        <text>1</text>
1049        <feedback format="html">
1050          <text></text>
1051        </feedback>
1052      </answer>
1053      <answer fraction="100" format="plain_text">
1054        <text>2</text>
1055        <feedback format="html">
1056          <text></text>
1057        </feedback>
1058      </answer>
1059      <answer fraction="0" format="plain_text">
1060        <text>3</text>
1061        <feedback format="html">
1062          <text></text>
1063        </feedback>
1064      </answer>
1065      <answer fraction="100" format="plain_text">
1066        <text>4</text>
1067        <feedback format="html">
1068          <text></text>
1069        </feedback>
1070      </answer>
1071      <hint format="html">
1072        <text>Hint 1.</text>
1073      </hint>
1074      <hint format="html">
1075        <text>Hint 2.</text>
1076      </hint>
1077    </question>
1078  ';
1079  
1080          $this->assert_same_xml($expectedxml, $xml);
1081      }
1082  
1083      public function test_import_numerical_19() {
1084          $xml = '  <question type="numerical">
1085      <name>
1086        <text>Numerical question</text>
1087      </name>
1088      <questiontext format="html">
1089        <text>What is the answer?</text>
1090      </questiontext>
1091      <generalfeedback>
1092        <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text>
1093      </generalfeedback>
1094      <defaultgrade>1</defaultgrade>
1095      <penalty>0.1</penalty>
1096      <hidden>0</hidden>
1097      <answer fraction="100">
1098        <text>42</text>
1099        <feedback>
1100          <text>Well done!</text>
1101        </feedback>
1102        <tolerance>0.001</tolerance>
1103      </answer>
1104      <answer fraction="0">
1105        <text>13</text>
1106        <feedback>
1107          <text>What were you thinking?!</text>
1108        </feedback>
1109        <tolerance>1</tolerance>
1110      </answer>
1111      <answer fraction="0">
1112        <text>*</text>
1113        <feedback>
1114          <text>Completely wrong.</text>
1115        </feedback>
1116        <tolerance></tolerance>
1117      </answer>
1118    </question>';
1119          $xmldata = xmlize($xml);
1120  
1121          $importer = new qformat_xml();
1122          $q = $importer->import_numerical($xmldata['question']);
1123  
1124          $expectedq = new \stdClass();
1125          $expectedq->qtype = 'numerical';
1126          $expectedq->name = 'Numerical question';
1127          $expectedq->questiontext = 'What is the answer?';
1128          $expectedq->questiontextformat = FORMAT_HTML;
1129          $expectedq->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
1130          $expectedq->generalfeedbackformat = FORMAT_HTML;
1131          $expectedq->defaultmark = 1;
1132          $expectedq->length = 1;
1133          $expectedq->penalty = 0.1;
1134  
1135          $expectedq->answer = array('42', '13', '*');
1136          $expectedq->fraction = array(1, 0, 0);
1137          $expectedq->feedback = array(
1138              array('text' => 'Well done!',
1139                      'format' => FORMAT_HTML),
1140              array('text' => 'What were you thinking?!',
1141                      'format' => FORMAT_HTML),
1142              array('text' => 'Completely wrong.',
1143                      'format' => FORMAT_HTML));
1144          $expectedq->tolerance = array(0.001, 1, '');
1145  
1146          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1147      }
1148  
1149      public function test_export_numerical() {
1150          question_bank::load_question_definition_classes('numerical');
1151  
1152          $qdata = new \stdClass();
1153          $qdata->id = 123;
1154          $qdata->contextid = \context_system::instance()->id;
1155          $qdata->qtype = 'numerical';
1156          $qdata->name = 'Numerical question';
1157          $qdata->questiontext = 'What is the answer?';
1158          $qdata->questiontextformat = FORMAT_HTML;
1159          $qdata->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
1160          $qdata->generalfeedbackformat = FORMAT_HTML;
1161          $qdata->defaultmark = 1;
1162          $qdata->length = 1;
1163          $qdata->penalty = 0.1;
1164          $qdata->hidden = 0;
1165          $qdata->idnumber = null;
1166  
1167          $qdata->options = new \stdClass();
1168          $qdata->options->answers = array(
1169              13 => new qtype_numerical_answer(13, '42', 1, 'Well done!',
1170                      FORMAT_HTML, 0.001),
1171              14 => new qtype_numerical_answer(14, '13', 0, 'What were you thinking?!',
1172                      FORMAT_HTML, 1),
1173              15 => new qtype_numerical_answer(15, '*', 0, 'Completely wrong.',
1174                      FORMAT_HTML, ''),
1175          );
1176  
1177          $qdata->options->units = array();
1178  
1179          $exporter = new qformat_xml();
1180          $xml = $exporter->writequestion($qdata);
1181  
1182          $expectedxml = '<!-- question: 123  -->
1183    <question type="numerical">
1184      <name>
1185        <text>Numerical question</text>
1186      </name>
1187      <questiontext format="html">
1188        <text>What is the answer?</text>
1189      </questiontext>
1190      <generalfeedback format="html">
1191        <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text>
1192      </generalfeedback>
1193      <defaultgrade>1</defaultgrade>
1194      <penalty>0.1</penalty>
1195      <hidden>0</hidden>
1196      <idnumber></idnumber>
1197      <answer fraction="100" format="plain_text">
1198        <text>42</text>
1199        <feedback format="html">
1200          <text>Well done!</text>
1201        </feedback>
1202        <tolerance>0.001</tolerance>
1203      </answer>
1204      <answer fraction="0" format="plain_text">
1205        <text>13</text>
1206        <feedback format="html">
1207          <text>What were you thinking?!</text>
1208        </feedback>
1209        <tolerance>1</tolerance>
1210      </answer>
1211      <answer fraction="0" format="plain_text">
1212        <text>*</text>
1213        <feedback format="html">
1214          <text>Completely wrong.</text>
1215        </feedback>
1216        <tolerance>0</tolerance>
1217      </answer>
1218    </question>
1219  ';
1220  
1221          $this->assert_same_xml($expectedxml, $xml);
1222      }
1223  
1224      public function test_import_shortanswer_19() {
1225          $xml = '  <question type="shortanswer">
1226      <name>
1227        <text>Short answer question</text>
1228      </name>
1229      <questiontext format="html">
1230        <text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text>
1231      </questiontext>
1232      <generalfeedback>
1233        <text>The answer is Beta.</text>
1234      </generalfeedback>
1235      <defaultgrade>1</defaultgrade>
1236      <penalty>0.3333333</penalty>
1237      <hidden>0</hidden>
1238      <usecase>0</usecase>
1239      <answer fraction="100" format="plain_text">
1240        <text>Beta</text>
1241        <feedback>
1242          <text>Well done!</text>
1243        </feedback>
1244      </answer>
1245      <answer fraction="0" format="plain_text">
1246        <text>*</text>
1247        <feedback>
1248          <text>Doh!</text>
1249        </feedback>
1250      </answer>
1251      <hint>
1252        <text>Hint 1</text>
1253      </hint>
1254      <hint>
1255        <text>Hint 2</text>
1256      </hint>
1257    </question>';
1258          $xmldata = xmlize($xml);
1259  
1260          $importer = new qformat_xml();
1261          $q = $importer->import_shortanswer($xmldata['question']);
1262  
1263          $expectedq = new \stdClass();
1264          $expectedq->qtype = 'shortanswer';
1265          $expectedq->name = 'Short answer question';
1266          $expectedq->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.';
1267          $expectedq->questiontextformat = FORMAT_HTML;
1268          $expectedq->generalfeedback = 'The answer is Beta.';
1269          $expectedq->usecase = false;
1270          $expectedq->defaultmark = 1;
1271          $expectedq->length = 1;
1272          $expectedq->penalty = 0.3333333;
1273  
1274          $expectedq->answer = array('Beta', '*');
1275          $expectedq->fraction = array(1, 0);
1276          $expectedq->feedback = array(
1277              array('text' => 'Well done!', 'format' => FORMAT_HTML),
1278              array('text' => 'Doh!', 'format' => FORMAT_HTML));
1279  
1280          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1281      }
1282  
1283      public function test_export_shortanswer() {
1284          $qdata = new \stdClass();
1285          $qdata->id = 123;
1286          $qdata->contextid = \context_system::instance()->id;
1287          $qdata->qtype = 'shortanswer';
1288          $qdata->name = 'Short answer question';
1289          $qdata->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.';
1290          $qdata->questiontextformat = FORMAT_HTML;
1291          $qdata->generalfeedback = 'The answer is Beta.';
1292          $qdata->generalfeedbackformat = FORMAT_HTML;
1293          $qdata->defaultmark = 1;
1294          $qdata->length = 1;
1295          $qdata->penalty = 0.3333333;
1296          $qdata->hidden = 0;
1297          $qdata->idnumber = null;
1298  
1299          $qdata->options = new \stdClass();
1300          $qdata->options->usecase = 0;
1301  
1302          $qdata->options->answers = array(
1303              13 => new question_answer(13, 'Beta', 1, 'Well done!', FORMAT_HTML),
1304              14 => new question_answer(14, '*', 0, 'Doh!', FORMAT_HTML),
1305          );
1306  
1307          $qdata->hints = array(
1308              new question_hint(0, 'Hint 1', FORMAT_HTML),
1309              new question_hint(0, 'Hint 2', FORMAT_HTML),
1310          );
1311  
1312          $exporter = new qformat_xml();
1313          $xml = $exporter->writequestion($qdata);
1314  
1315          $expectedxml = '<!-- question: 123  -->
1316    <question type="shortanswer">
1317      <name>
1318        <text>Short answer question</text>
1319      </name>
1320      <questiontext format="html">
1321        <text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text>
1322      </questiontext>
1323      <generalfeedback format="html">
1324        <text>The answer is Beta.</text>
1325      </generalfeedback>
1326      <defaultgrade>1</defaultgrade>
1327      <penalty>0.3333333</penalty>
1328      <hidden>0</hidden>
1329      <idnumber></idnumber>
1330      <usecase>0</usecase>
1331      <answer fraction="100" format="plain_text">
1332        <text>Beta</text>
1333        <feedback format="html">
1334          <text>Well done!</text>
1335        </feedback>
1336      </answer>
1337      <answer fraction="0" format="plain_text">
1338        <text>*</text>
1339        <feedback format="html">
1340          <text>Doh!</text>
1341        </feedback>
1342      </answer>
1343      <hint format="html">
1344        <text>Hint 1</text>
1345      </hint>
1346      <hint format="html">
1347        <text>Hint 2</text>
1348      </hint>
1349    </question>
1350  ';
1351  
1352          $this->assert_same_xml($expectedxml, $xml);
1353      }
1354  
1355      public function test_import_truefalse_19() {
1356          $xml = '  <question type="truefalse">
1357      <name>
1358        <text>True false question</text>
1359      </name>
1360      <questiontext format="html">
1361        <text>The answer is true.</text>
1362      </questiontext>
1363      <generalfeedback>
1364        <text>General feedback: You should have chosen true.</text>
1365      </generalfeedback>
1366      <defaultgrade>1</defaultgrade>
1367      <penalty>1</penalty>
1368      <hidden>0</hidden>
1369      <answer fraction="100">
1370        <text>true</text>
1371        <feedback>
1372          <text>Well done!</text>
1373        </feedback>
1374      </answer>
1375      <answer fraction="0">
1376        <text>false</text>
1377        <feedback>
1378          <text>Doh!</text>
1379        </feedback>
1380      </answer>
1381    </question>';
1382          $xmldata = xmlize($xml);
1383  
1384          $importer = new qformat_xml();
1385          $q = $importer->import_truefalse($xmldata['question']);
1386  
1387          $expectedq = new \stdClass();
1388          $expectedq->qtype = 'truefalse';
1389          $expectedq->name = 'True false question';
1390          $expectedq->questiontext = 'The answer is true.';
1391          $expectedq->questiontextformat = FORMAT_HTML;
1392          $expectedq->generalfeedback = 'General feedback: You should have chosen true.';
1393          $expectedq->defaultmark = 1;
1394          $expectedq->length = 1;
1395          $expectedq->penalty = 1;
1396  
1397          $expectedq->feedbacktrue = array('text' => 'Well done!',
1398                  'format' => FORMAT_HTML);
1399          $expectedq->feedbackfalse = array('text' => 'Doh!',
1400                  'format' => FORMAT_HTML);
1401          $expectedq->correctanswer = true;
1402  
1403          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1404      }
1405  
1406      public function test_import_truefalse_with_idnumber() {
1407          $xml = '  <question type="truefalse">
1408      <name>
1409        <text>True false question</text>
1410      </name>
1411      <questiontext format="html">
1412        <text>The answer is true.</text>
1413      </questiontext>
1414      <generalfeedback>
1415        <text>General feedback: You should have chosen true.</text>
1416      </generalfeedback>
1417      <defaultgrade>1</defaultgrade>
1418      <penalty>1</penalty>
1419      <hidden>0</hidden>
1420      <idnumber>TestIdNum1</idnumber>
1421      <answer fraction="100">
1422        <text>true</text>
1423        <feedback>
1424          <text>Well done!</text>
1425        </feedback>
1426      </answer>
1427      <answer fraction="0">
1428        <text>false</text>
1429        <feedback>
1430          <text>Doh!</text>
1431        </feedback>
1432      </answer>
1433    </question>';
1434          $xmldata = xmlize($xml);
1435  
1436          $importer = new qformat_xml();
1437          $q = $importer->import_truefalse($xmldata['question']);
1438  
1439          $expectedq = new \stdClass();
1440          $expectedq->qtype = 'truefalse';
1441          $expectedq->name = 'True false question';
1442          $expectedq->questiontext = 'The answer is true.';
1443          $expectedq->questiontextformat = FORMAT_HTML;
1444          $expectedq->generalfeedback = 'General feedback: You should have chosen true.';
1445          $expectedq->defaultmark = 1;
1446          $expectedq->length = 1;
1447          $expectedq->penalty = 1;
1448          $expectedq->idnumber = 'TestIdNum1';
1449  
1450          $expectedq->feedbacktrue = array('text' => 'Well done!',
1451                  'format' => FORMAT_HTML);
1452          $expectedq->feedbackfalse = array('text' => 'Doh!',
1453                  'format' => FORMAT_HTML);
1454          $expectedq->correctanswer = true;
1455  
1456          $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1457      }
1458  
1459      public function test_export_truefalse() {
1460          $qdata = new \stdClass();
1461          $qdata->id = 12;
1462          $qdata->contextid = \context_system::instance()->id;
1463          $qdata->qtype = 'truefalse';
1464          $qdata->name = 'True false question';
1465          $qdata->questiontext = 'The answer is true.';
1466          $qdata->questiontextformat = FORMAT_HTML;
1467          $qdata->generalfeedback = 'General feedback: You should have chosen true.';
1468          $qdata->generalfeedbackformat = FORMAT_HTML;
1469          $qdata->defaultmark = 1;
1470          $qdata->length = 1;
1471          $qdata->penalty = 1;
1472          $qdata->hidden = 0;
1473          $qdata->idnumber = null;
1474  
1475          $qdata->options = new \stdClass();
1476          $qdata->options->answers = array(
1477              1 => new question_answer(1, 'True', 1, 'Well done!', FORMAT_HTML),
1478              2 => new question_answer(2, 'False', 0, 'Doh!', FORMAT_HTML),
1479          );
1480          $qdata->options->trueanswer = 1;
1481          $qdata->options->falseanswer = 2;
1482  
1483          $exporter = new qformat_xml();
1484          $xml = $exporter->writequestion($qdata);
1485  
1486          $expectedxml = '<!-- question: 12  -->
1487    <question type="truefalse">
1488      <name>
1489        <text>True false question</text>
1490      </name>
1491      <questiontext format="html">
1492        <text>The answer is true.</text>
1493      </questiontext>
1494      <generalfeedback format="html">
1495        <text>General feedback: You should have chosen true.</text>
1496      </generalfeedback>
1497      <defaultgrade>1</defaultgrade>
1498      <penalty>1</penalty>
1499      <hidden>0</hidden>
1500      <idnumber></idnumber>
1501      <answer fraction="100" format="plain_text">
1502        <text>true</text>
1503        <feedback format="html">
1504          <text>Well done!</text>
1505        </feedback>
1506      </answer>
1507      <answer fraction="0" format="plain_text">
1508        <text>false</text>
1509        <feedback format="html">
1510          <text>Doh!</text>
1511        </feedback>
1512      </answer>
1513    </question>
1514  ';
1515  
1516          $this->assert_same_xml($expectedxml, $xml);
1517      }
1518  
1519      public function test_export_truefalse_with_idnumber() {
1520          $qdata = new \stdClass();
1521          $qdata->id = 12;
1522          $qdata->contextid = \context_system::instance()->id;
1523          $qdata->qtype = 'truefalse';
1524          $qdata->name = 'True false question';
1525          $qdata->questiontext = 'The answer is true.';
1526          $qdata->questiontextformat = FORMAT_HTML;
1527          $qdata->generalfeedback = 'General feedback: You should have chosen true.';
1528          $qdata->generalfeedbackformat = FORMAT_HTML;
1529          $qdata->defaultmark = 1;
1530          $qdata->length = 1;
1531          $qdata->penalty = 1;
1532          $qdata->hidden = 0;
1533          $qdata->idnumber = 'TestIDNum2';
1534  
1535          $qdata->options = new \stdClass();
1536          $qdata->options->answers = array(
1537                  1 => new question_answer(1, 'True', 1, 'Well done!', FORMAT_HTML),
1538                  2 => new question_answer(2, 'False', 0, 'Doh!', FORMAT_HTML),
1539          );
1540          $qdata->options->trueanswer = 1;
1541          $qdata->options->falseanswer = 2;
1542  
1543          $exporter = new qformat_xml();
1544          $xml = $exporter->writequestion($qdata);
1545  
1546          $expectedxml = '<!-- question: 12  -->
1547    <question type="truefalse">
1548      <name>
1549        <text>True false question</text>
1550      </name>
1551      <questiontext format="html">
1552        <text>The answer is true.</text>
1553      </questiontext>
1554      <generalfeedback format="html">
1555        <text>General feedback: You should have chosen true.</text>
1556      </generalfeedback>
1557      <defaultgrade>1</defaultgrade>
1558      <penalty>1</penalty>
1559      <hidden>0</hidden>
1560      <idnumber>TestIDNum2</idnumber>
1561      <answer fraction="100" format="plain_text">
1562        <text>true</text>
1563        <feedback format="html">
1564          <text>Well done!</text>
1565        </feedback>
1566      </answer>
1567      <answer fraction="0" format="plain_text">
1568        <text>false</text>
1569        <feedback format="html">
1570          <text>Doh!</text>
1571        </feedback>
1572      </answer>
1573    </question>
1574  ';
1575  
1576          $this->assert_same_xml($expectedxml, $xml);
1577      }
1578  
1579      public function test_import_multianswer() {
1580          $xml = '  <question type="cloze">
1581      <name>
1582        <text>Simple multianswer</text>
1583      </name>
1584      <questiontext format="html">
1585        <text><![CDATA[Complete this opening line of verse: "The {1:SHORTANSWER:Dog#Wrong, silly!~=Owl#Well done!~*#Wrong answer} and the {1:MULTICHOICE:Bow-wow#You seem to have a dog obsessions!~Wiggly worm#Now you are just being ridiculous!~=Pussy-cat#Well done!} went to sea".]]></text>
1586      </questiontext>
1587      <generalfeedback format="html">
1588        <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".]]></text>
1589      </generalfeedback>
1590      <penalty>0.5</penalty>
1591      <hidden>0</hidden>
1592      <hint format="html">
1593        <text>Hint 1</text>
1594      </hint>
1595      <hint format="html">
1596        <text>Hint 2</text>
1597      </hint>
1598      <tags>
1599        <tag><text>tagCloze</text></tag>
1600        <tag><text>tagTest</text></tag>
1601      </tags>
1602    </question>
1603  ';
1604          $xmldata = xmlize($xml);
1605  
1606          $importer = new qformat_xml();
1607          $q = $importer->import_multianswer($xmldata['question']);
1608  
1609          // Annoyingly, import works in a weird way (it duplicates code, rather
1610          // than just calling save_question) so we cannot use
1611          // \test_question_maker::get_question_form_data('multianswer', 'twosubq').
1612          $expectedqa = new \stdClass();
1613          $expectedqa->name = 'Simple multianswer';
1614          $expectedqa->qtype = 'multianswer';
1615          $expectedqa->questiontext = 'Complete this opening line of verse: "The {#1} and the {#2} went to sea".';
1616          $expectedqa->generalfeedback =
1617                  'General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".';
1618          $expectedqa->defaultmark = 2;
1619          $expectedqa->penalty = 0.5;
1620  
1621          $expectedqa->hint = array(
1622              array('text' => 'Hint 1', 'format' => FORMAT_HTML),
1623              array('text' => 'Hint 2', 'format' => FORMAT_HTML),
1624          );
1625  
1626          $sa = new \stdClass();
1627  
1628          $sa->questiontext = array('text' => '{1:SHORTANSWER:Dog#Wrong, silly!~=Owl#Well done!~*#Wrong answer}',
1629                  'format' => FORMAT_HTML, 'itemid' => null);
1630          $sa->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1631          $sa->defaultmark = 1.0;
1632          $sa->qtype = 'shortanswer';
1633          $sa->usecase = 0;
1634  
1635          $sa->answer = array('Dog', 'Owl', '*');
1636          $sa->fraction = array(0, 1, 0);
1637          $sa->feedback = array(
1638              array('text' => 'Wrong, silly!', 'format' => FORMAT_HTML, 'itemid' => null),
1639              array('text' => 'Well done!',    'format' => FORMAT_HTML, 'itemid' => null),
1640              array('text' => 'Wrong answer',  'format' => FORMAT_HTML, 'itemid' => null),
1641          );
1642  
1643          $mc = new \stdClass();
1644  
1645          $mc->generalfeedback = '';
1646          $mc->questiontext = array('text' => '{1:MULTICHOICE:Bow-wow#You seem to have a dog obsessions!~' .
1647                  'Wiggly worm#Now you are just being ridiculous!~=Pussy-cat#Well done!}',
1648                  'format' => FORMAT_HTML, 'itemid' => null);
1649          $mc->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1650          $mc->defaultmark = 1.0;
1651          $mc->qtype = 'multichoice';
1652  
1653          $mc->layout = 0;
1654          $mc->single = 1;
1655          $mc->shuffleanswers = 0;
1656          $mc->correctfeedback =          array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1657          $mc->partiallycorrectfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1658          $mc->incorrectfeedback =        array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1659          $mc->answernumbering = 0;
1660  
1661          $mc->answer = array(
1662              array('text' => 'Bow-wow',     'format' => FORMAT_HTML, 'itemid' => null),
1663              array('text' => 'Wiggly worm', 'format' => FORMAT_HTML, 'itemid' => null),
1664              array('text' => 'Pussy-cat',   'format' => FORMAT_HTML, 'itemid' => null),
1665          );
1666          $mc->fraction = array(0, 0, 1);
1667          $mc->feedback = array(
1668              array('text' => 'You seem to have a dog obsessions!', 'format' => FORMAT_HTML, 'itemid' => null),
1669              array('text' => 'Now you are just being ridiculous!', 'format' => FORMAT_HTML, 'itemid' => null),
1670              array('text' => 'Well done!',                         'format' => FORMAT_HTML, 'itemid' => null),
1671          );
1672  
1673          $expectedqa->options = new \stdClass();
1674          $expectedqa->options->questions = array(
1675              1 => $sa,
1676              2 => $mc,
1677          );
1678          $expectedqa->tags = array('tagCloze', 'tagTest');
1679  
1680          $this->assertEquals($expectedqa->hint, $q->hint);
1681          $this->assertEquals($expectedqa->options->questions[1], $q->options->questions[1]);
1682          $this->assertEquals($expectedqa->options->questions[2], $q->options->questions[2]);
1683          $this->assert(new question_check_specified_fields_expectation($expectedqa), $q);
1684      }
1685  
1686      public function test_export_multianswer() {
1687          $qdata = \test_question_maker::get_question_data('multianswer', 'twosubq');
1688          $qdata->contextid = \context_system::instance()->id;
1689          $exporter = new qformat_xml();
1690          $xml = $exporter->writequestion($qdata);
1691  
1692          $expectedxml = '<!-- question: 0  -->
1693    <question type="cloze">
1694      <name>
1695        <text>Simple multianswer</text>
1696      </name>
1697      <questiontext format="html">
1698        <text><![CDATA[Complete this opening line of verse: "The {1:SHORTANSWER:Dog#Wrong, silly!~=Owl#Well done!~*#Wrong answer} and the {1:MULTICHOICE:Bow-wow#You seem to have a dog obsessions!~Wiggly worm#Now you are just being ridiculous!~=Pussy-cat#Well done!} went to sea".]]></text>
1699      </questiontext>
1700      <generalfeedback format="html">
1701        <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea]]></text>
1702      </generalfeedback>
1703      <penalty>0.3333333</penalty>
1704      <hidden>0</hidden>
1705      <idnumber></idnumber>
1706      <hint format="html">
1707        <text>Hint 1</text>
1708      </hint>
1709      <hint format="html">
1710        <text>Hint 2</text>
1711      </hint>
1712    </question>
1713  ';
1714  
1715          $this->assert_same_xml($expectedxml, $xml);
1716      }
1717  
1718      public function test_export_multianswer_withdollars() {
1719          $qdata = \test_question_maker::get_question_data('multianswer', 'dollarsigns');
1720          $qdata->contextid = \context_system::instance()->id;
1721          $exporter = new qformat_xml();
1722          $xml = $exporter->writequestion($qdata);
1723  
1724          $expectedxml = '<!-- question: 0  -->
1725    <question type="cloze">
1726      <name>
1727        <text>Multianswer with $s</text>
1728      </name>
1729      <questiontext format="html">
1730        <text>Which is the right order? {1:MULTICHOICE:=y,y,$3~$3,y,y}</text>
1731      </questiontext>
1732      <generalfeedback format="html">
1733        <text></text>
1734      </generalfeedback>
1735      <penalty>0.3333333</penalty>
1736      <hidden>0</hidden>
1737      <idnumber></idnumber>
1738    </question>
1739  ';
1740  
1741          $this->assert_same_xml($expectedxml, $xml);
1742      }
1743  
1744      public function test_import_files_as_draft() {
1745          $this->resetAfterTest();
1746          $this->setAdminUser();
1747  
1748          $xml = <<<END
1749  <questiontext format="html">
1750      <text><![CDATA[<p><a href="@@PLUGINFILE@@/moodle.txt">This text file</a> contains the word 'Moodle'.</p>]]></text>
1751      <file name="moodle.txt" encoding="base64">TW9vZGxl</file>
1752  </questiontext>
1753  END;
1754  
1755          $textxml = xmlize($xml);
1756          $qo = new \stdClass();
1757  
1758          $importer = new qformat_xml();
1759          $draftitemid = $importer->import_files_as_draft($textxml['questiontext']['#']['file']);
1760          $files = file_get_drafarea_files($draftitemid);
1761  
1762          $this->assertEquals(1, count($files->list));
1763  
1764          $file = $files->list[0];
1765          $this->assertEquals('moodle.txt', $file->filename);
1766          $this->assertEquals('/',          $file->filepath);
1767          $this->assertEquals(6,            $file->size);
1768      }
1769  
1770      public function test_import_truefalse_wih_files() {
1771          $this->resetAfterTest();
1772          $this->setAdminUser();
1773  
1774          $xml = '<question type="truefalse">
1775      <name>
1776        <text>truefalse</text>
1777      </name>
1778      <questiontext format="html">
1779        <text><![CDATA[<p><a href="@@PLUGINFILE@@/myfolder/moodle.txt">This text file</a> contains the word Moodle.</p>]]></text>
1780  <file name="moodle.txt" path="/myfolder/" encoding="base64">TW9vZGxl</file>
1781      </questiontext>
1782      <generalfeedback format="html">
1783        <text><![CDATA[<p>For further information, see the documentation about Moodle.</p>]]></text>
1784  </generalfeedback>
1785      <defaultgrade>1.0000000</defaultgrade>
1786      <penalty>1.0000000</penalty>
1787      <hidden>0</hidden>
1788      <answer fraction="100" format="moodle_auto_format">
1789        <text>true</text>
1790        <feedback format="html">
1791          <text></text>
1792        </feedback>
1793      </answer>
1794      <answer fraction="0" format="moodle_auto_format">
1795        <text>false</text>
1796        <feedback format="html">
1797          <text></text>
1798        </feedback>
1799      </answer>
1800    </question>';
1801          $xmldata = xmlize($xml);
1802  
1803          $importer = new qformat_xml();
1804          $q = $importer->import_truefalse($xmldata['question']);
1805  
1806          $draftitemid = $q->questiontextitemid;
1807          $files = file_get_drafarea_files($draftitemid, '/myfolder/');
1808  
1809          $this->assertEquals(1, count($files->list));
1810  
1811          $file = $files->list[0];
1812          $this->assertEquals('moodle.txt', $file->filename);
1813          $this->assertEquals('/myfolder/', $file->filepath);
1814          $this->assertEquals(6,            $file->size);
1815      }
1816  
1817      public function test_create_dummy_question() {
1818  
1819          $testobject = new mock_qformat_xml();
1820          $categoryname = 'name1';
1821          $categoryinfo = new \stdClass();
1822          $categoryinfo->info = 'info1';
1823          $categoryinfo->infoformat = 'infoformat1';
1824          $categoryinfo->idnumber = null;
1825          $dummyquestion = $testobject->mock_create_dummy_question_representing_category($categoryname, $categoryinfo);
1826  
1827          $this->assertEquals('category', $dummyquestion->qtype);
1828          $this->assertEquals($categoryname, $dummyquestion->category);
1829          $this->assertEquals($categoryinfo->info, $dummyquestion->info);
1830          $this->assertEquals($categoryinfo->infoformat, $dummyquestion->infoformat);
1831          $this->assertEquals('Switch category to ' . $categoryname, $dummyquestion->name);
1832          $this->assertEquals(0, $dummyquestion->id);
1833          $this->assertEquals('', $dummyquestion->questiontextformat);
1834          $this->assertEquals(0, $dummyquestion->contextid);
1835      }
1836  }
1837  
1838  /**
1839   * Class mock_qformat_xml exists only to enable testing of the create dummy question category.
1840   * @package    qformat_xml
1841   * @copyright  2018 The Open University
1842   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1843   */
1844  class mock_qformat_xml extends qformat_xml {
1845      /**
1846       * Make public an otherwise protected function.
1847       * @param string $categoryname the name of the category
1848       * @param object $categoryinfo description of the category
1849       */
1850      public function mock_create_dummy_question_representing_category(string $categoryname, $categoryinfo) {
1851          return $this->create_dummy_question_representing_category($categoryname, $categoryinfo);
1852      }
1853  }