fbaa93d00c6f909631c3d027fd2bea13b3375693
[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   </question>';
306         $xmldata = xmlize($xml);
308         $importer = new qformat_xml();
309         $q = $importer->import_description($xmldata['question']);
311         $expectedq = new stdClass();
312         $expectedq->qtype = 'description';
313         $expectedq->name = 'A description';
314         $expectedq->questiontext = 'The question text.';
315         $expectedq->questiontextformat = FORMAT_HTML;
316         $expectedq->generalfeedback = 'Here is some general feedback.';
317         $expectedq->defaultmark = 0;
318         $expectedq->length = 0;
319         $expectedq->penalty = 0;
321         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
322     }
324     public function test_export_description() {
325         $qdata = new stdClass();
326         $qdata->id = 123;
327         $qdata->contextid = 0;
328         $qdata->qtype = 'description';
329         $qdata->name = 'A description';
330         $qdata->questiontext = 'The question text.';
331         $qdata->questiontextformat = FORMAT_HTML;
332         $qdata->generalfeedback = 'Here is some general feedback.';
333         $qdata->generalfeedbackformat = FORMAT_HTML;
334         $qdata->defaultmark = 0;
335         $qdata->length = 0;
336         $qdata->penalty = 0;
337         $qdata->hidden = 0;
339         $exporter = new qformat_xml();
340         $xml = $exporter->writequestion($qdata);
342         $expectedxml = '<!-- question: 123  -->
343   <question type="description">
344     <name>
345       <text>A description</text>
346     </name>
347     <questiontext format="html">
348       <text>The question text.</text>
349     </questiontext>
350     <generalfeedback format="html">
351       <text>Here is some general feedback.</text>
352     </generalfeedback>
353     <defaultgrade>0</defaultgrade>
354     <penalty>0</penalty>
355     <hidden>0</hidden>
356   </question>
357 ';
359         $this->assert_same_xml($expectedxml, $xml);
360     }
362     public function test_import_essay_20() {
363         $xml = '  <question type="essay">
364     <name>
365       <text>An essay</text>
366     </name>
367     <questiontext format="moodle_auto_format">
368       <text>Write something.</text>
369     </questiontext>
370     <generalfeedback>
371       <text>I hope you wrote something interesting.</text>
372     </generalfeedback>
373     <defaultgrade>1</defaultgrade>
374     <penalty>0</penalty>
375     <hidden>0</hidden>
376   </question>';
377         $xmldata = xmlize($xml);
379         $importer = new qformat_xml();
380         $q = $importer->import_essay($xmldata['question']);
382         $expectedq = new stdClass();
383         $expectedq->qtype = 'essay';
384         $expectedq->name = 'An essay';
385         $expectedq->questiontext = 'Write something.';
386         $expectedq->questiontextformat = FORMAT_MOODLE;
387         $expectedq->generalfeedback = 'I hope you wrote something interesting.';
388         $expectedq->defaultmark = 1;
389         $expectedq->length = 1;
390         $expectedq->penalty = 0;
391         $expectedq->responseformat = 'editor';
392         $expectedq->responserequired = 1;
393         $expectedq->responsefieldlines = 15;
394         $expectedq->attachments = 0;
395         $expectedq->attachmentsrequired = 0;
396         $expectedq->graderinfo['text'] = '';
397         $expectedq->graderinfo['format'] = FORMAT_MOODLE;
398         $expectedq->responsetemplate['text'] = '';
399         $expectedq->responsetemplate['format'] = FORMAT_MOODLE;
401         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
402     }
404     public function test_import_essay_21() {
405         $xml = '  <question type="essay">
406     <name>
407       <text>An essay</text>
408     </name>
409     <questiontext format="moodle_auto_format">
410       <text>Write something.</text>
411     </questiontext>
412     <generalfeedback>
413       <text>I hope you wrote something interesting.</text>
414     </generalfeedback>
415     <defaultgrade>1</defaultgrade>
416     <penalty>0</penalty>
417     <hidden>0</hidden>
418     <responseformat>monospaced</responseformat>
419     <responserequired>0</responserequired>
420     <responsefieldlines>42</responsefieldlines>
421     <attachments>-1</attachments>
422     <attachmentsrequired>1</attachmentsrequired>
423     <graderinfo format="html">
424         <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text>
425     </graderinfo>
426     <responsetemplate format="html">
427         <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text>
428     </responsetemplate>
429   </question>';
430         $xmldata = xmlize($xml);
432         $importer = new qformat_xml();
433         $q = $importer->import_essay($xmldata['question']);
435         $expectedq = new stdClass();
436         $expectedq->qtype = 'essay';
437         $expectedq->name = 'An essay';
438         $expectedq->questiontext = 'Write something.';
439         $expectedq->questiontextformat = FORMAT_MOODLE;
440         $expectedq->generalfeedback = 'I hope you wrote something interesting.';
441         $expectedq->defaultmark = 1;
442         $expectedq->length = 1;
443         $expectedq->penalty = 0;
444         $expectedq->responseformat = 'monospaced';
445         $expectedq->responserequired = 0;
446         $expectedq->responsefieldlines = 42;
447         $expectedq->attachments = -1;
448         $expectedq->attachmentsrequired = 1;
449         $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>';
450         $expectedq->graderinfo['format'] = FORMAT_HTML;
451         $expectedq->responsetemplate['text'] = '<p>Here is something <b>really</b> interesting.</p>';
452         $expectedq->responsetemplate['format'] = FORMAT_HTML;
454         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
455     }
457     public function test_export_essay() {
458         $qdata = new stdClass();
459         $qdata->id = 123;
460         $qdata->contextid = 0;
461         $qdata->qtype = 'essay';
462         $qdata->name = 'An essay';
463         $qdata->questiontext = 'Write something.';
464         $qdata->questiontextformat = FORMAT_MOODLE;
465         $qdata->generalfeedback = 'I hope you wrote something interesting.';
466         $qdata->generalfeedbackformat = FORMAT_MOODLE;
467         $qdata->defaultmark = 1;
468         $qdata->length = 1;
469         $qdata->penalty = 0;
470         $qdata->hidden = 0;
471         $qdata->options = new stdClass();
472         $qdata->options->id = 456;
473         $qdata->options->questionid = 123;
474         $qdata->options->responseformat = 'monospaced';
475         $qdata->options->responserequired = 0;
476         $qdata->options->responsefieldlines = 42;
477         $qdata->options->attachments = -1;
478         $qdata->options->attachmentsrequired = 1;
479         $qdata->options->graderinfo = '<p>Grade <b>generously</b>!</p>';
480         $qdata->options->graderinfoformat = FORMAT_HTML;
481         $qdata->options->responsetemplate = '<p>Here is something <b>really</b> interesting.</p>';
482         $qdata->options->responsetemplateformat = FORMAT_HTML;
483         $exporter = new qformat_xml();
484         $xml = $exporter->writequestion($qdata);
486         $expectedxml = '<!-- question: 123  -->
487   <question type="essay">
488     <name>
489       <text>An essay</text>
490     </name>
491     <questiontext format="moodle_auto_format">
492       <text>Write something.</text>
493     </questiontext>
494     <generalfeedback format="moodle_auto_format">
495       <text>I hope you wrote something interesting.</text>
496     </generalfeedback>
497     <defaultgrade>1</defaultgrade>
498     <penalty>0</penalty>
499     <hidden>0</hidden>
500     <responseformat>monospaced</responseformat>
501     <responserequired>0</responserequired>
502     <responsefieldlines>42</responsefieldlines>
503     <attachments>-1</attachments>
504     <attachmentsrequired>1</attachmentsrequired>
505     <graderinfo format="html">
506       <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text>
507     </graderinfo>
508     <responsetemplate format="html">
509       <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text>
510     </responsetemplate>
511   </question>
512 ';
514         $this->assert_same_xml($expectedxml, $xml);
515     }
517     public function test_import_match_19() {
518         $xml = '  <question type="matching">
519     <name>
520       <text>Matching question</text>
521     </name>
522     <questiontext format="html">
523       <text>Match the upper and lower case letters.</text>
524     </questiontext>
525     <generalfeedback>
526       <text>The answer is A -> a, B -> b and C -> c.</text>
527     </generalfeedback>
528     <defaultgrade>1</defaultgrade>
529     <penalty>0.3333333</penalty>
530     <hidden>0</hidden>
531     <shuffleanswers>false</shuffleanswers>
532     <correctfeedback>
533       <text>Well done.</text>
534     </correctfeedback>
535     <partiallycorrectfeedback>
536       <text>Not entirely.</text>
537     </partiallycorrectfeedback>
538     <incorrectfeedback>
539       <text>Completely wrong!</text>
540     </incorrectfeedback>
541     <subquestion>
542       <text>A</text>
543       <answer>
544         <text>a</text>
545       </answer>
546     </subquestion>
547     <subquestion>
548       <text>B</text>
549       <answer>
550         <text>b</text>
551       </answer>
552     </subquestion>
553     <subquestion>
554       <text>C</text>
555       <answer>
556         <text>c</text>
557       </answer>
558     </subquestion>
559     <subquestion>
560       <text></text>
561       <answer>
562         <text>d</text>
563       </answer>
564     </subquestion>
565     <hint>
566       <text>Hint 1</text>
567       <shownumcorrect />
568     </hint>
569     <hint>
570       <text></text>
571       <shownumcorrect />
572       <clearwrong />
573     </hint>
574   </question>';
575         $xmldata = xmlize($xml);
577         $importer = new qformat_xml();
578         $q = $importer->import_match($xmldata['question']);
580         $expectedq = new stdClass();
581         $expectedq->qtype = 'match';
582         $expectedq->name = 'Matching question';
583         $expectedq->questiontext = 'Match the upper and lower case letters.';
584         $expectedq->questiontextformat = FORMAT_HTML;
585         $expectedq->correctfeedback = array('text' => 'Well done.',
586                 'format' => FORMAT_HTML);
587         $expectedq->partiallycorrectfeedback = array('text' => 'Not entirely.',
588                 'format' => FORMAT_HTML);
589         $expectedq->shownumcorrect = false;
590         $expectedq->incorrectfeedback = array('text' => 'Completely wrong!',
591                 'format' => FORMAT_HTML);
592         $expectedq->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
593         $expectedq->generalfeedbackformat = FORMAT_HTML;
594         $expectedq->defaultmark = 1;
595         $expectedq->length = 1;
596         $expectedq->penalty = 0.3333333;
597         $expectedq->shuffleanswers = 0;
598         $expectedq->subquestions = array(
599             array('text' => 'A', 'format' => FORMAT_HTML),
600             array('text' => 'B', 'format' => FORMAT_HTML),
601             array('text' => 'C', 'format' => FORMAT_HTML),
602             array('text' => '', 'format' => FORMAT_HTML));
603         $expectedq->subanswers = array('a', 'b', 'c', 'd');
604         $expectedq->hint = array(
605             array('text' => 'Hint 1', 'format' => FORMAT_HTML),
606             array('text' => '', 'format' => FORMAT_HTML),
607         );
608         $expectedq->hintshownumcorrect = array(true, true);
609         $expectedq->hintclearwrong = array(false, true);
611         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
612     }
614     public function test_export_match() {
615         $qdata = new stdClass();
616         $qdata->id = 123;
617         $qdata->contextid = 0;
618         $qdata->qtype = 'match';
619         $qdata->name = 'Matching question';
620         $qdata->questiontext = 'Match the upper and lower case letters.';
621         $qdata->questiontextformat = FORMAT_HTML;
622         $qdata->generalfeedback = 'The answer is A -> a, B -> b and C -> c.';
623         $qdata->generalfeedbackformat = FORMAT_HTML;
624         $qdata->defaultmark = 1;
625         $qdata->length = 1;
626         $qdata->penalty = 0.3333333;
627         $qdata->hidden = 0;
629         $qdata->options = new stdClass();
630         $qdata->options->shuffleanswers = 1;
631         $qdata->options->correctfeedback = 'Well done.';
632         $qdata->options->correctfeedbackformat = FORMAT_HTML;
633         $qdata->options->partiallycorrectfeedback = 'Not entirely.';
634         $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML;
635         $qdata->options->shownumcorrect = false;
636         $qdata->options->incorrectfeedback = 'Completely wrong!';
637         $qdata->options->incorrectfeedbackformat = FORMAT_HTML;
639         $subq1 = new stdClass();
640         $subq1->id = -4;
641         $subq1->questiontext = 'A';
642         $subq1->questiontextformat = FORMAT_HTML;
643         $subq1->answertext = 'a';
645         $subq2 = new stdClass();
646         $subq2->id = -3;
647         $subq2->questiontext = 'B';
648         $subq2->questiontextformat = FORMAT_HTML;
649         $subq2->answertext = 'b';
651         $subq3 = new stdClass();
652         $subq3->id = -2;
653         $subq3->questiontext = 'C';
654         $subq3->questiontextformat = FORMAT_HTML;
655         $subq3->answertext = 'c';
657         $subq4 = new stdClass();
658         $subq4->id = -1;
659         $subq4->questiontext = '';
660         $subq4->questiontextformat = FORMAT_HTML;
661         $subq4->answertext = 'd';
663         $qdata->options->subquestions = array(
664                 $subq1, $subq2, $subq3, $subq4);
666         $qdata->hints = array(
667             new question_hint_with_parts(0, 'Hint 1', FORMAT_HTML, true, false),
668             new question_hint_with_parts(0, '', FORMAT_HTML, true, true),
669         );
671         $exporter = new qformat_xml();
672         $xml = $exporter->writequestion($qdata);
674         $expectedxml = '<!-- question: 123  -->
675   <question type="matching">
676     <name>
677       <text>Matching question</text>
678     </name>
679     <questiontext format="html">
680       <text>Match the upper and lower case letters.</text>
681     </questiontext>
682     <generalfeedback format="html">
683       <text><![CDATA[The answer is A -> a, B -> b and C -> c.]]></text>
684     </generalfeedback>
685     <defaultgrade>1</defaultgrade>
686     <penalty>0.3333333</penalty>
687     <hidden>0</hidden>
688     <shuffleanswers>true</shuffleanswers>
689     <correctfeedback format="html">
690       <text>Well done.</text>
691     </correctfeedback>
692     <partiallycorrectfeedback format="html">
693       <text>Not entirely.</text>
694     </partiallycorrectfeedback>
695     <incorrectfeedback format="html">
696       <text>Completely wrong!</text>
697     </incorrectfeedback>
698     <subquestion format="html">
699       <text>A</text>
700       <answer>
701         <text>a</text>
702       </answer>
703     </subquestion>
704     <subquestion format="html">
705       <text>B</text>
706       <answer>
707         <text>b</text>
708       </answer>
709     </subquestion>
710     <subquestion format="html">
711       <text>C</text>
712       <answer>
713         <text>c</text>
714       </answer>
715     </subquestion>
716     <subquestion format="html">
717       <text></text>
718       <answer>
719         <text>d</text>
720       </answer>
721     </subquestion>
722     <hint format="html">
723       <text>Hint 1</text>
724       <shownumcorrect/>
725     </hint>
726     <hint format="html">
727       <text></text>
728       <shownumcorrect/>
729       <clearwrong/>
730     </hint>
731   </question>
732 ';
734         $this->assert_same_xml($expectedxml, $xml);
735     }
737     public function test_import_multichoice_19() {
738         $xml = '  <question type="multichoice">
739     <name>
740       <text>Multiple choice question</text>
741     </name>
742     <questiontext format="html">
743       <text>Which are the even numbers?</text>
744     </questiontext>
745     <generalfeedback>
746       <text>The even numbers are 2 and 4.</text>
747     </generalfeedback>
748     <defaultgrade>2</defaultgrade>
749     <penalty>0.3333333</penalty>
750     <hidden>0</hidden>
751     <single>false</single>
752     <shuffleanswers>false</shuffleanswers>
753     <answernumbering>abc</answernumbering>
754     <correctfeedback>
755       <text><![CDATA[<p>Your answer is correct.</p>]]></text>
756     </correctfeedback>
757     <partiallycorrectfeedback>
758       <text><![CDATA[<p>Your answer is partially correct.</p>]]></text>
759     </partiallycorrectfeedback>
760     <incorrectfeedback>
761       <text><![CDATA[<p>Your answer is incorrect.</p>]]></text>
762     </incorrectfeedback>
763     <shownumcorrect/>
764     <answer fraction="0">
765       <text>1</text>
766       <feedback>
767         <text></text>
768       </feedback>
769     </answer>
770     <answer fraction="100">
771       <text>2</text>
772       <feedback>
773         <text></text>
774       </feedback>
775     </answer>
776     <answer fraction="0">
777       <text>3</text>
778       <feedback>
779         <text></text>
780       </feedback>
781     </answer>
782     <answer fraction="100">
783       <text>4</text>
784       <feedback>
785         <text></text>
786       </feedback>
787     </answer>
788     <hint>
789       <text>Hint 1.</text>
790     </hint>
791     <hint>
792       <text>Hint 2.</text>
793     </hint>
794   </question>';
795         $xmldata = xmlize($xml);
797         $importer = new qformat_xml();
798         $q = $importer->import_multichoice($xmldata['question']);
800         $expectedq = new stdClass();
801         $expectedq->qtype = 'multichoice';
802         $expectedq->name = 'Multiple choice question';
803         $expectedq->questiontext = 'Which are the even numbers?';
804         $expectedq->questiontextformat = FORMAT_HTML;
805         $expectedq->correctfeedback = array(
806                 'text'   => '<p>Your answer is correct.</p>',
807                 'format' => FORMAT_HTML);
808         $expectedq->shownumcorrect = false;
809         $expectedq->partiallycorrectfeedback = array(
810                 'text'   => '<p>Your answer is partially correct.</p>',
811                 'format' => FORMAT_HTML);
812         $expectedq->shownumcorrect = true;
813         $expectedq->incorrectfeedback = array(
814                 'text'   => '<p>Your answer is incorrect.</p>',
815                 'format' => FORMAT_HTML);
816         $expectedq->generalfeedback = 'The even numbers are 2 and 4.';
817         $expectedq->defaultmark = 2;
818         $expectedq->length = 1;
819         $expectedq->penalty = 0.3333333;
820         $expectedq->shuffleanswers = 0;
821         $expectedq->single = false;
823         $expectedq->answer = array(
824             array('text' => '1', 'format' => FORMAT_HTML),
825             array('text' => '2', 'format' => FORMAT_HTML),
826             array('text' => '3', 'format' => FORMAT_HTML),
827             array('text' => '4', 'format' => FORMAT_HTML));
828         $expectedq->fraction = array(0, 1, 0, 1);
829         $expectedq->feedback = array(
830             array('text' => '', 'format' => FORMAT_HTML),
831             array('text' => '', 'format' => FORMAT_HTML),
832             array('text' => '', 'format' => FORMAT_HTML),
833             array('text' => '', 'format' => FORMAT_HTML));
835         $expectedq->hint = array(
836             array('text' => 'Hint 1.', 'format' => FORMAT_HTML),
837             array('text' => 'Hint 2.', 'format' => FORMAT_HTML),
838         );
839         $expectedq->hintshownumcorrect = array(false, false);
840         $expectedq->hintclearwrong = array(false, false);
842         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
843     }
845     public function test_export_multichoice() {
846         $qdata = new stdClass();
847         $qdata->id = 123;
848         $qdata->contextid = 0;
849         $qdata->qtype = 'multichoice';
850         $qdata->name = 'Multiple choice question';
851         $qdata->questiontext = 'Which are the even numbers?';
852         $qdata->questiontextformat = FORMAT_HTML;
853         $qdata->generalfeedback = 'The even numbers are 2 and 4.';
854         $qdata->generalfeedbackformat = FORMAT_HTML;
855         $qdata->defaultmark = 2;
856         $qdata->length = 1;
857         $qdata->penalty = 0.3333333;
858         $qdata->hidden = 0;
860         $qdata->options = new stdClass();
861         $qdata->options->single = 0;
862         $qdata->options->shuffleanswers = 0;
863         $qdata->options->answernumbering = 'abc';
864         $qdata->options->correctfeedback = '<p>Your answer is correct.</p>';
865         $qdata->options->correctfeedbackformat = FORMAT_HTML;
866         $qdata->options->partiallycorrectfeedback = '<p>Your answer is partially correct.</p>';
867         $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML;
868         $qdata->options->shownumcorrect = 1;
869         $qdata->options->incorrectfeedback = '<p>Your answer is incorrect.</p>';
870         $qdata->options->incorrectfeedbackformat = FORMAT_HTML;
872         $qdata->options->answers = array(
873             13 => new question_answer(13, '1', 0, '', FORMAT_HTML),
874             14 => new question_answer(14, '2', 1, '', FORMAT_HTML),
875             15 => new question_answer(15, '3', 0, '', FORMAT_HTML),
876             16 => new question_answer(16, '4', 1, '', FORMAT_HTML),
877         );
879         $qdata->hints = array(
880             new question_hint_with_parts(0, 'Hint 1.', FORMAT_HTML, false, false),
881             new question_hint_with_parts(0, 'Hint 2.', FORMAT_HTML, false, false),
882         );
884         $exporter = new qformat_xml();
885         $xml = $exporter->writequestion($qdata);
887         $expectedxml = '<!-- question: 123  -->
888   <question type="multichoice">
889     <name>
890       <text>Multiple choice question</text>
891     </name>
892     <questiontext format="html">
893       <text>Which are the even numbers?</text>
894     </questiontext>
895     <generalfeedback format="html">
896       <text>The even numbers are 2 and 4.</text>
897     </generalfeedback>
898     <defaultgrade>2</defaultgrade>
899     <penalty>0.3333333</penalty>
900     <hidden>0</hidden>
901     <single>false</single>
902     <shuffleanswers>false</shuffleanswers>
903     <answernumbering>abc</answernumbering>
904     <correctfeedback format="html">
905       <text><![CDATA[<p>Your answer is correct.</p>]]></text>
906     </correctfeedback>
907     <partiallycorrectfeedback format="html">
908       <text><![CDATA[<p>Your answer is partially correct.</p>]]></text>
909     </partiallycorrectfeedback>
910     <incorrectfeedback format="html">
911       <text><![CDATA[<p>Your answer is incorrect.</p>]]></text>
912     </incorrectfeedback>
913     <shownumcorrect/>
914     <answer fraction="0" format="plain_text">
915       <text>1</text>
916       <feedback format="html">
917         <text></text>
918       </feedback>
919     </answer>
920     <answer fraction="100" format="plain_text">
921       <text>2</text>
922       <feedback format="html">
923         <text></text>
924       </feedback>
925     </answer>
926     <answer fraction="0" format="plain_text">
927       <text>3</text>
928       <feedback format="html">
929         <text></text>
930       </feedback>
931     </answer>
932     <answer fraction="100" format="plain_text">
933       <text>4</text>
934       <feedback format="html">
935         <text></text>
936       </feedback>
937     </answer>
938     <hint format="html">
939       <text>Hint 1.</text>
940     </hint>
941     <hint format="html">
942       <text>Hint 2.</text>
943     </hint>
944   </question>
945 ';
947         $this->assert_same_xml($expectedxml, $xml);
948     }
950     public function test_import_numerical_19() {
951         $xml = '  <question type="numerical">
952     <name>
953       <text>Numerical question</text>
954     </name>
955     <questiontext format="html">
956       <text>What is the answer?</text>
957     </questiontext>
958     <generalfeedback>
959       <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text>
960     </generalfeedback>
961     <defaultgrade>1</defaultgrade>
962     <penalty>0.1</penalty>
963     <hidden>0</hidden>
964     <answer fraction="100">
965       <text>42</text>
966       <feedback>
967         <text>Well done!</text>
968       </feedback>
969       <tolerance>0.001</tolerance>
970     </answer>
971     <answer fraction="0">
972       <text>13</text>
973       <feedback>
974         <text>What were you thinking?!</text>
975       </feedback>
976       <tolerance>1</tolerance>
977     </answer>
978     <answer fraction="0">
979       <text>*</text>
980       <feedback>
981         <text>Completely wrong.</text>
982       </feedback>
983       <tolerance></tolerance>
984     </answer>
985   </question>';
986         $xmldata = xmlize($xml);
988         $importer = new qformat_xml();
989         $q = $importer->import_numerical($xmldata['question']);
991         $expectedq = new stdClass();
992         $expectedq->qtype = 'numerical';
993         $expectedq->name = 'Numerical question';
994         $expectedq->questiontext = 'What is the answer?';
995         $expectedq->questiontextformat = FORMAT_HTML;
996         $expectedq->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
997         $expectedq->generalfeedbackformat = FORMAT_HTML;
998         $expectedq->defaultmark = 1;
999         $expectedq->length = 1;
1000         $expectedq->penalty = 0.1;
1002         $expectedq->answer = array('42', '13', '*');
1003         $expectedq->fraction = array(1, 0, 0);
1004         $expectedq->feedback = array(
1005             array('text' => 'Well done!',
1006                     'format' => FORMAT_HTML),
1007             array('text' => 'What were you thinking?!',
1008                     'format' => FORMAT_HTML),
1009             array('text' => 'Completely wrong.',
1010                     'format' => FORMAT_HTML));
1011         $expectedq->tolerance = array(0.001, 1, 0);
1013         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1014     }
1016     public function test_export_numerical() {
1017         question_bank::load_question_definition_classes('numerical');
1019         $qdata = new stdClass();
1020         $qdata->id = 123;
1021         $qdata->contextid = 0;
1022         $qdata->qtype = 'numerical';
1023         $qdata->name = 'Numerical question';
1024         $qdata->questiontext = 'What is the answer?';
1025         $qdata->questiontextformat = FORMAT_HTML;
1026         $qdata->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.';
1027         $qdata->generalfeedbackformat = FORMAT_HTML;
1028         $qdata->defaultmark = 1;
1029         $qdata->length = 1;
1030         $qdata->penalty = 0.1;
1031         $qdata->hidden = 0;
1033         $qdata->options = new stdClass();
1034         $qdata->options->answers = array(
1035             13 => new qtype_numerical_answer(13, '42', 1, 'Well done!',
1036                     FORMAT_HTML, 0.001),
1037             14 => new qtype_numerical_answer(14, '13', 0, 'What were you thinking?!',
1038                     FORMAT_HTML, 1),
1039             15 => new qtype_numerical_answer(15, '*', 0, 'Completely wrong.',
1040                     FORMAT_HTML, ''),
1041         );
1043         $qdata->options->units = array();
1045         $exporter = new qformat_xml();
1046         $xml = $exporter->writequestion($qdata);
1048         $expectedxml = '<!-- question: 123  -->
1049   <question type="numerical">
1050     <name>
1051       <text>Numerical question</text>
1052     </name>
1053     <questiontext format="html">
1054       <text>What is the answer?</text>
1055     </questiontext>
1056     <generalfeedback format="html">
1057       <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text>
1058     </generalfeedback>
1059     <defaultgrade>1</defaultgrade>
1060     <penalty>0.1</penalty>
1061     <hidden>0</hidden>
1062     <answer fraction="100" format="plain_text">
1063       <text>42</text>
1064       <feedback format="html">
1065         <text>Well done!</text>
1066       </feedback>
1067       <tolerance>0.001</tolerance>
1068     </answer>
1069     <answer fraction="0" format="plain_text">
1070       <text>13</text>
1071       <feedback format="html">
1072         <text>What were you thinking?!</text>
1073       </feedback>
1074       <tolerance>1</tolerance>
1075     </answer>
1076     <answer fraction="0" format="plain_text">
1077       <text>*</text>
1078       <feedback format="html">
1079         <text>Completely wrong.</text>
1080       </feedback>
1081       <tolerance>0</tolerance>
1082     </answer>
1083   </question>
1084 ';
1086         $this->assert_same_xml($expectedxml, $xml);
1087     }
1089     public function test_import_shortanswer_19() {
1090         $xml = '  <question type="shortanswer">
1091     <name>
1092       <text>Short answer question</text>
1093     </name>
1094     <questiontext format="html">
1095       <text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text>
1096     </questiontext>
1097     <generalfeedback>
1098       <text>The answer is Beta.</text>
1099     </generalfeedback>
1100     <defaultgrade>1</defaultgrade>
1101     <penalty>0.3333333</penalty>
1102     <hidden>0</hidden>
1103     <usecase>0</usecase>
1104     <answer fraction="100" format="plain_text">
1105       <text>Beta</text>
1106       <feedback>
1107         <text>Well done!</text>
1108       </feedback>
1109     </answer>
1110     <answer fraction="0" format="plain_text">
1111       <text>*</text>
1112       <feedback>
1113         <text>Doh!</text>
1114       </feedback>
1115     </answer>
1116     <hint>
1117       <text>Hint 1</text>
1118     </hint>
1119     <hint>
1120       <text>Hint 2</text>
1121     </hint>
1122   </question>';
1123         $xmldata = xmlize($xml);
1125         $importer = new qformat_xml();
1126         $q = $importer->import_shortanswer($xmldata['question']);
1128         $expectedq = new stdClass();
1129         $expectedq->qtype = 'shortanswer';
1130         $expectedq->name = 'Short answer question';
1131         $expectedq->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.';
1132         $expectedq->questiontextformat = FORMAT_HTML;
1133         $expectedq->generalfeedback = 'The answer is Beta.';
1134         $expectedq->usecase = false;
1135         $expectedq->defaultmark = 1;
1136         $expectedq->length = 1;
1137         $expectedq->penalty = 0.3333333;
1139         $expectedq->answer = array('Beta', '*');
1140         $expectedq->fraction = array(1, 0);
1141         $expectedq->feedback = array(
1142             array('text' => 'Well done!', 'format' => FORMAT_HTML),
1143             array('text' => 'Doh!', 'format' => FORMAT_HTML));
1145         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1146     }
1148     public function test_export_shortanswer() {
1149         $qdata = new stdClass();
1150         $qdata->id = 123;
1151         $qdata->contextid = 0;
1152         $qdata->qtype = 'shortanswer';
1153         $qdata->name = 'Short answer question';
1154         $qdata->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.';
1155         $qdata->questiontextformat = FORMAT_HTML;
1156         $qdata->generalfeedback = 'The answer is Beta.';
1157         $qdata->generalfeedbackformat = FORMAT_HTML;
1158         $qdata->defaultmark = 1;
1159         $qdata->length = 1;
1160         $qdata->penalty = 0.3333333;
1161         $qdata->hidden = 0;
1163         $qdata->options = new stdClass();
1164         $qdata->options->usecase = 0;
1166         $qdata->options->answers = array(
1167             13 => new question_answer(13, 'Beta', 1, 'Well done!', FORMAT_HTML),
1168             14 => new question_answer(14, '*', 0, 'Doh!', FORMAT_HTML),
1169         );
1171         $qdata->hints = array(
1172             new question_hint(0, 'Hint 1', FORMAT_HTML),
1173             new question_hint(0, 'Hint 2', FORMAT_HTML),
1174         );
1176         $exporter = new qformat_xml();
1177         $xml = $exporter->writequestion($qdata);
1179         $expectedxml = '<!-- question: 123  -->
1180   <question type="shortanswer">
1181     <name>
1182       <text>Short answer question</text>
1183     </name>
1184     <questiontext format="html">
1185       <text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text>
1186     </questiontext>
1187     <generalfeedback format="html">
1188       <text>The answer is Beta.</text>
1189     </generalfeedback>
1190     <defaultgrade>1</defaultgrade>
1191     <penalty>0.3333333</penalty>
1192     <hidden>0</hidden>
1193     <usecase>0</usecase>
1194     <answer fraction="100" format="plain_text">
1195       <text>Beta</text>
1196       <feedback format="html">
1197         <text>Well done!</text>
1198       </feedback>
1199     </answer>
1200     <answer fraction="0" format="plain_text">
1201       <text>*</text>
1202       <feedback format="html">
1203         <text>Doh!</text>
1204       </feedback>
1205     </answer>
1206     <hint format="html">
1207       <text>Hint 1</text>
1208     </hint>
1209     <hint format="html">
1210       <text>Hint 2</text>
1211     </hint>
1212   </question>
1213 ';
1215         $this->assert_same_xml($expectedxml, $xml);
1216     }
1218     public function test_import_truefalse_19() {
1219         $xml = '  <question type="truefalse">
1220     <name>
1221       <text>True false question</text>
1222     </name>
1223     <questiontext format="html">
1224       <text>The answer is true.</text>
1225     </questiontext>
1226     <generalfeedback>
1227       <text>General feedback: You should have chosen true.</text>
1228     </generalfeedback>
1229     <defaultgrade>1</defaultgrade>
1230     <penalty>1</penalty>
1231     <hidden>0</hidden>
1232     <answer fraction="100">
1233       <text>true</text>
1234       <feedback>
1235         <text>Well done!</text>
1236       </feedback>
1237     </answer>
1238     <answer fraction="0">
1239       <text>false</text>
1240       <feedback>
1241         <text>Doh!</text>
1242       </feedback>
1243     </answer>
1244   </question>';
1245         $xmldata = xmlize($xml);
1247         $importer = new qformat_xml();
1248         $q = $importer->import_truefalse($xmldata['question']);
1250         $expectedq = new stdClass();
1251         $expectedq->qtype = 'truefalse';
1252         $expectedq->name = 'True false question';
1253         $expectedq->questiontext = 'The answer is true.';
1254         $expectedq->questiontextformat = FORMAT_HTML;
1255         $expectedq->generalfeedback = 'General feedback: You should have chosen true.';
1256         $expectedq->defaultmark = 1;
1257         $expectedq->length = 1;
1258         $expectedq->penalty = 1;
1260         $expectedq->feedbacktrue = array('text' => 'Well done!',
1261                 'format' => FORMAT_HTML);
1262         $expectedq->feedbackfalse = array('text' => 'Doh!',
1263                 'format' => FORMAT_HTML);
1264         $expectedq->correctanswer = true;
1266         $this->assert(new question_check_specified_fields_expectation($expectedq), $q);
1267     }
1269     public function test_export_truefalse() {
1270         $qdata = new stdClass();
1271         $qdata->id = 12;
1272         $qdata->contextid = 0;
1273         $qdata->qtype = 'truefalse';
1274         $qdata->name = 'True false question';
1275         $qdata->questiontext = 'The answer is true.';
1276         $qdata->questiontextformat = FORMAT_HTML;
1277         $qdata->generalfeedback = 'General feedback: You should have chosen true.';
1278         $qdata->generalfeedbackformat = FORMAT_HTML;
1279         $qdata->defaultmark = 1;
1280         $qdata->length = 1;
1281         $qdata->penalty = 1;
1282         $qdata->hidden = 0;
1284         $qdata->options = new stdClass();
1285         $qdata->options->answers = array(
1286             1 => new question_answer(1, 'True', 1, 'Well done!', FORMAT_HTML),
1287             2 => new question_answer(2, 'False', 0, 'Doh!', FORMAT_HTML),
1288         );
1289         $qdata->options->trueanswer = 1;
1290         $qdata->options->falseanswer = 2;
1292         $exporter = new qformat_xml();
1293         $xml = $exporter->writequestion($qdata);
1295         $expectedxml = '<!-- question: 12  -->
1296   <question type="truefalse">
1297     <name>
1298       <text>True false question</text>
1299     </name>
1300     <questiontext format="html">
1301       <text>The answer is true.</text>
1302     </questiontext>
1303     <generalfeedback format="html">
1304       <text>General feedback: You should have chosen true.</text>
1305     </generalfeedback>
1306     <defaultgrade>1</defaultgrade>
1307     <penalty>1</penalty>
1308     <hidden>0</hidden>
1309     <answer fraction="100" format="plain_text">
1310       <text>true</text>
1311       <feedback format="html">
1312         <text>Well done!</text>
1313       </feedback>
1314     </answer>
1315     <answer fraction="0" format="plain_text">
1316       <text>false</text>
1317       <feedback format="html">
1318         <text>Doh!</text>
1319       </feedback>
1320     </answer>
1321   </question>
1322 ';
1324         $this->assert_same_xml($expectedxml, $xml);
1325     }
1327     public function test_import_multianswer() {
1328         $xml = '  <question type="cloze">
1329     <name>
1330       <text>Simple multianswer</text>
1331     </name>
1332     <questiontext format="html">
1333       <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>
1334     </questiontext>
1335     <generalfeedback format="html">
1336       <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".]]></text>
1337     </generalfeedback>
1338     <penalty>0.5</penalty>
1339     <hidden>0</hidden>
1340     <hint format="html">
1341       <text>Hint 1</text>
1342     </hint>
1343     <hint format="html">
1344       <text>Hint 2</text>
1345     </hint>
1346   </question>
1347 ';
1348         $xmldata = xmlize($xml);
1350         $importer = new qformat_xml();
1351         $q = $importer->import_multianswer($xmldata['question']);
1353         // Annoyingly, import works in a weird way (it duplicates code, rather
1354         // than just calling save_question) so we cannot use
1355         // test_question_maker::get_question_form_data('multianswer', 'twosubq').
1356         $expectedqa = new stdClass();
1357         $expectedqa->name = 'Simple multianswer';
1358         $expectedqa->qtype = 'multianswer';
1359         $expectedqa->questiontext = 'Complete this opening line of verse: "The {#1} and the {#2} went to sea".';
1360         $expectedqa->generalfeedback =
1361                 'General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".';
1362         $expectedqa->defaultmark = 2;
1363         $expectedqa->penalty = 0.5;
1365         $expectedqa->hint = array(
1366             array('text' => 'Hint 1', 'format' => FORMAT_HTML),
1367             array('text' => 'Hint 2', 'format' => FORMAT_HTML),
1368         );
1370         $sa = new stdClass();
1372         $sa->questiontext = array('text' => '{1:SHORTANSWER:Dog#Wrong, silly!~=Owl#Well done!~*#Wrong answer}',
1373                 'format' => FORMAT_HTML, 'itemid' => null);
1374         $sa->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1375         $sa->defaultmark = 1.0;
1376         $sa->qtype = 'shortanswer';
1377         $sa->usecase = 0;
1379         $sa->answer = array('Dog', 'Owl', '*');
1380         $sa->fraction = array(0, 1, 0);
1381         $sa->feedback = array(
1382             array('text' => 'Wrong, silly!', 'format' => FORMAT_HTML, 'itemid' => null),
1383             array('text' => 'Well done!',    'format' => FORMAT_HTML, 'itemid' => null),
1384             array('text' => 'Wrong answer',  'format' => FORMAT_HTML, 'itemid' => null),
1385         );
1387         $mc = new stdClass();
1389         $mc->generalfeedback = '';
1390         $mc->questiontext = array('text' => '{1:MULTICHOICE:Bow-wow#You seem to have a dog obsessions!~' .
1391                 'Wiggly worm#Now you are just being ridiculous!~=Pussy-cat#Well done!}',
1392                 'format' => FORMAT_HTML, 'itemid' => null);
1393         $mc->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1394         $mc->defaultmark = 1.0;
1395         $mc->qtype = 'multichoice';
1397         $mc->layout = 0;
1398         $mc->single = 1;
1399         $mc->shuffleanswers = 1;
1400         $mc->correctfeedback =          array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1401         $mc->partiallycorrectfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1402         $mc->incorrectfeedback =        array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null);
1403         $mc->answernumbering = 0;
1405         $mc->answer = array(
1406             array('text' => 'Bow-wow',     'format' => FORMAT_HTML, 'itemid' => null),
1407             array('text' => 'Wiggly worm', 'format' => FORMAT_HTML, 'itemid' => null),
1408             array('text' => 'Pussy-cat',   'format' => FORMAT_HTML, 'itemid' => null),
1409         );
1410         $mc->fraction = array(0, 0, 1);
1411         $mc->feedback = array(
1412             array('text' => 'You seem to have a dog obsessions!', 'format' => FORMAT_HTML, 'itemid' => null),
1413             array('text' => 'Now you are just being ridiculous!', 'format' => FORMAT_HTML, 'itemid' => null),
1414             array('text' => 'Well done!',                         'format' => FORMAT_HTML, 'itemid' => null),
1415         );
1417         $expectedqa->options = new stdClass();
1418         $expectedqa->options->questions = array(
1419             1 => $sa,
1420             2 => $mc,
1421         );
1423         $this->assertEquals($expectedqa->hint, $q->hint);
1424         $this->assertEquals($expectedqa->options->questions[1], $q->options->questions[1]);
1425         $this->assertEquals($expectedqa->options->questions[2], $q->options->questions[2]);
1426         $this->assert(new question_check_specified_fields_expectation($expectedqa), $q);
1427     }
1429     public function test_export_multianswer() {
1430         $qdata = test_question_maker::get_question_data('multianswer', 'twosubq');
1432         $exporter = new qformat_xml();
1433         $xml = $exporter->writequestion($qdata);
1435         $expectedxml = '<!-- question: 0  -->
1436   <question type="cloze">
1437     <name>
1438       <text>Simple multianswer</text>
1439     </name>
1440     <questiontext format="html">
1441       <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>
1442     </questiontext>
1443     <generalfeedback format="html">
1444       <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea]]></text>
1445     </generalfeedback>
1446     <penalty>0.3333333</penalty>
1447     <hidden>0</hidden>
1448     <hint format="html">
1449       <text>Hint 1</text>
1450     </hint>
1451     <hint format="html">
1452       <text>Hint 2</text>
1453     </hint>
1454   </question>
1455 ';
1457         $this->assert_same_xml($expectedxml, $xml);
1458     }
1460     public function test_export_multianswer_withdollars() {
1461         $qdata = test_question_maker::get_question_data('multianswer', 'dollarsigns');
1463         $exporter = new qformat_xml();
1464         $xml = $exporter->writequestion($qdata);
1466         $expectedxml = '<!-- question: 0  -->
1467   <question type="cloze">
1468     <name>
1469       <text>Multianswer with $s</text>
1470     </name>
1471     <questiontext format="html">
1472       <text>Which is the right order? {1:MULTICHOICE:=y,y,$3~$3,y,y}</text>
1473     </questiontext>
1474     <generalfeedback format="html">
1475       <text></text>
1476     </generalfeedback>
1477     <penalty>0.3333333</penalty>
1478     <hidden>0</hidden>
1479   </question>
1480 ';
1482         $this->assert_same_xml($expectedxml, $xml);
1483     }
1485     public function test_import_files_as_draft() {
1486         $this->resetAfterTest();
1487         $this->setAdminUser();
1489         $xml = <<<END
1490 <questiontext format="html">
1491     <text><![CDATA[<p><a href="@@PLUGINFILE@@/moodle.txt">This text file</a> contains the word 'Moodle'.</p>]]></text>
1492     <file name="moodle.txt" encoding="base64">TW9vZGxl</file>
1493 </questiontext>
1494 END;
1496         $textxml = xmlize($xml);
1497         $qo = new stdClass();
1499         $importer = new qformat_xml();
1500         $draftitemid = $importer->import_files_as_draft($textxml['questiontext']['#']['file']);
1501         $files = file_get_drafarea_files($draftitemid);
1503         $this->assertEquals(1, count($files->list));
1505         $file = $files->list[0];
1506         $this->assertEquals('moodle.txt', $file->filename);
1507         $this->assertEquals('/',          $file->filepath);
1508         $this->assertEquals(6,            $file->size);
1509     }
1511     public function test_import_truefalse_wih_files() {
1512         $this->resetAfterTest();
1513         $this->setAdminUser();
1515         $xml = '<question type="truefalse">
1516     <name>
1517       <text>truefalse</text>
1518     </name>
1519     <questiontext format="html">
1520       <text><![CDATA[<p><a href="@@PLUGINFILE@@/myfolder/moodle.txt">This text file</a> contains the word Moodle.</p>]]></text>
1521 <file name="moodle.txt" path="/myfolder/" encoding="base64">TW9vZGxl</file>
1522     </questiontext>
1523     <generalfeedback format="html">
1524       <text><![CDATA[<p>For further information, see the documentation about Moodle.</p>]]></text>
1525 </generalfeedback>
1526     <defaultgrade>1.0000000</defaultgrade>
1527     <penalty>1.0000000</penalty>
1528     <hidden>0</hidden>
1529     <answer fraction="100" format="moodle_auto_format">
1530       <text>true</text>
1531       <feedback format="html">
1532         <text></text>
1533       </feedback>
1534     </answer>
1535     <answer fraction="0" format="moodle_auto_format">
1536       <text>false</text>
1537       <feedback format="html">
1538         <text></text>
1539       </feedback>
1540     </answer>
1541   </question>';
1542         $xmldata = xmlize($xml);
1544         $importer = new qformat_xml();
1545         $q = $importer->import_truefalse($xmldata['question']);
1547         $draftitemid = $q->questiontextitemid;
1548         $files = file_get_drafarea_files($draftitemid, '/myfolder/');
1550         $this->assertEquals(1, count($files->list));
1552         $file = $files->list[0];
1553         $this->assertEquals('moodle.txt', $file->filename);
1554         $this->assertEquals('/myfolder/', $file->filepath);
1555         $this->assertEquals(6,            $file->size);
1556     }