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