MDL-50642 qformat_xml: fix import of tags in Cloze questions
[moodle.git] / question / format / xml / tests / xmlformat_test.php
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/>.
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  */
26 defined('MOODLE_INTERNAL') || die();
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');
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     }
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     }
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     }
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             }
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             }
108         } else {
109             $newvar = $var;
110         }
112         return $newvar;
113     }
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     }
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     }
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));
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     }
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));
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     }
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         );
168         $exporter = new qformat_xml();
169         $xml = $exporter->writequestion($q);
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     }
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';
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;
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         );
202         $exporter = new qformat_xml();
203         $xml = $exporter->writequestion($q);
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     }
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;
231         $questionxml = xmlize($xml);
232         $qo = new stdClass();
234         $importer = new qformat_xml();
235         $importer->import_hints($qo, $questionxml['question'], false, false, 'html');
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     }
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;
261         $questionxml = xmlize($xml);
262         $qo = new stdClass();
264         $importer = new qformat_xml();
265         $importer->import_hints($qo, $questionxml['question'], true, true, 'html');
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     }
277     public function test_import_no_hints_no_error() {
278         $xml = <<<END
279 <question>
280 </question>
281 END;
283         $questionxml = xmlize($xml);
284         $qo = new stdClass();
286         $importer = new qformat_xml();
287         $importer->import_hints($qo, $questionxml['question'], 'html');
289         $this->assertFalse(isset($qo->hint));
290     }
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);
313         $importer = new qformat_xml();
314         $q = $importer->import_description($xmldata['question']);
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');
327         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
328     }
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;
345         $exporter = new qformat_xml();
346         $xml = $exporter->writequestion($qdata);
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 ';
365         $this->assert_same_xml($expectedxml, $xml);
366     }
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);
390         $importer = new qformat_xml();
391         $q = $importer->import_essay($xmldata['question']);
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');
413         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
414     }
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);
449         $importer = new qformat_xml();
450         $q = $importer->import_essay($xmldata['question']);
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');
472         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
473     }
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);
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 ';
532         $this->assert_same_xml($expectedxml, $xml);
533     }
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);
599         $importer = new qformat_xml();
600         $q = $importer->import_match($xmldata['question']);
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');
634         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
635     }
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;
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;
662         $subq1 = new stdClass();
663         $subq1->id = -4;
664         $subq1->questiontext = 'A';
665         $subq1->questiontextformat = FORMAT_HTML;
666         $subq1->answertext = 'a';
668         $subq2 = new stdClass();
669         $subq2->id = -3;
670         $subq2->questiontext = 'B';
671         $subq2->questiontextformat = FORMAT_HTML;
672         $subq2->answertext = 'b';
674         $subq3 = new stdClass();
675         $subq3->id = -2;
676         $subq3->questiontext = 'C';
677         $subq3->questiontextformat = FORMAT_HTML;
678         $subq3->answertext = 'c';
680         $subq4 = new stdClass();
681         $subq4->id = -1;
682         $subq4->questiontext = '';
683         $subq4->questiontextformat = FORMAT_HTML;
684         $subq4->answertext = 'd';
686         $qdata->options->subquestions = array(
687                 $subq1, $subq2, $subq3, $subq4);
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         );
694         $exporter = new qformat_xml();
695         $xml = $exporter->writequestion($qdata);
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 ';
757         $this->assert_same_xml($expectedxml, $xml);
758     }
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);
820         $importer = new qformat_xml();
821         $q = $importer->import_multichoice($xmldata['question']);
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;
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));
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);
865         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
866     }
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;
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;
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         );
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         );
907         $exporter = new qformat_xml();
908         $xml = $exporter->writequestion($qdata);
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 ';
970         $this->assert_same_xml($expectedxml, $xml);
971     }
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);
1011         $importer = new qformat_xml();
1012         $q = $importer->import_numerical($xmldata['question']);
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;
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);
1036         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1037     }
1039     public function test_export_numerical() {
1040         question_bank::load_question_definition_classes('numerical');
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;
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         );
1066         $qdata->options->units = array();
1068         $exporter = new qformat_xml();
1069         $xml = $exporter->writequestion($qdata);
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 ';
1109         $this->assert_same_xml($expectedxml, $xml);
1110     }
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);
1148         $importer = new qformat_xml();
1149         $q = $importer->import_shortanswer($xmldata['question']);
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;
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));
1168         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1169     }
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;
1186         $qdata->options = new stdClass();
1187         $qdata->options->usecase = 0;
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         );
1194         $qdata->hints = array(
1195             new question_hint(0, 'Hint 1', FORMAT_HTML),
1196             new question_hint(0, 'Hint 2', FORMAT_HTML),
1197         );
1199         $exporter = new qformat_xml();
1200         $xml = $exporter->writequestion($qdata);
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 ';
1238         $this->assert_same_xml($expectedxml, $xml);
1239     }
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);
1270         $importer = new qformat_xml();
1271         $q = $importer->import_truefalse($xmldata['question']);
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;
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;
1289         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1290     }
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;
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;
1315         $exporter = new qformat_xml();
1316         $xml = $exporter->writequestion($qdata);
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 ';
1347         $this->assert_same_xml($expectedxml, $xml);
1348     }
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);
1377         $importer = new qformat_xml();
1378         $q = $importer->import_multianswer($xmldata['question']);
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;
1392         $expectedqa->hint = array(
1393             array('text' => 'Hint 1', 'format' => FORMAT_HTML),
1394             array('text' => 'Hint 2', 'format' => FORMAT_HTML),
1395         );
1397         $sa = new stdClass();
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;
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         );
1414         $mc = new stdClass();
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';
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;
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         );
1444         $expectedqa->options = new stdClass();
1445         $expectedqa->options->questions = array(
1446             1 => $sa,
1447             2 => $mc,
1448         );
1449         $expectedqa->tags = array('tagCloze', 'tagTest');
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     }
1457     public function test_export_multianswer() {
1458         $qdata = test_question_maker::get_question_data('multianswer', 'twosubq');
1460         $exporter = new qformat_xml();
1461         $xml = $exporter->writequestion($qdata);
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 ';
1485         $this->assert_same_xml($expectedxml, $xml);
1486     }
1488     public function test_export_multianswer_withdollars() {
1489         $qdata = test_question_maker::get_question_data('multianswer', 'dollarsigns');
1491         $exporter = new qformat_xml();
1492         $xml = $exporter->writequestion($qdata);
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 ';
1510         $this->assert_same_xml($expectedxml, $xml);
1511     }
1513     public function test_import_files_as_draft() {
1514         $this->resetAfterTest();
1515         $this->setAdminUser();
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;
1524         $textxml = xmlize($xml);
1525         $qo = new stdClass();
1527         $importer = new qformat_xml();
1528         $draftitemid = $importer->import_files_as_draft($textxml['questiontext']['#']['file']);
1529         $files = file_get_drafarea_files($draftitemid);
1531         $this->assertEquals(1, count($files->list));
1533         $file = $files->list[0];
1534         $this->assertEquals('moodle.txt', $file->filename);
1535         $this->assertEquals('/',          $file->filepath);
1536         $this->assertEquals(6,            $file->size);
1537     }
1539     public function test_import_truefalse_wih_files() {
1540         $this->resetAfterTest();
1541         $this->setAdminUser();
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);
1572         $importer = new qformat_xml();
1573         $q = $importer->import_truefalse($xmldata['question']);
1575         $draftitemid = $q->questiontextitemid;
1576         $files = file_get_drafarea_files($draftitemid, '/myfolder/');
1578         $this->assertEquals(1, count($files->list));
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     }