Search moodle.org's
Developer Documentation


  • Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).
  • Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).
  • minimum PHP 5.4.4 (always use latest PHP 5.4.x or 5.5.x on Windows - http://windows.php.net/download/), PHP 7 is NOT supported
  • Differences Between: [Versions 28 and 30] [Versions 28 and 31] [Versions 28 and 32] [Versions 28 and 33] [Versions 28 and 34] [Versions 28 and 35] [Versions 28 and 36] [Versions 28 and 37]

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

    Search This Site: