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