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