See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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->filetypeslist = null; 412 $expectedq->graderinfo['text'] = ''; 413 $expectedq->graderinfo['format'] = FORMAT_MOODLE; 414 $expectedq->responsetemplate['text'] = ''; 415 $expectedq->responsetemplate['format'] = FORMAT_MOODLE; 416 $expectedq->tags = array('tagEssay', 'tagEssay20', 'tagTest'); 417 418 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 419 } 420 421 public function test_import_essay_21() { 422 $xml = ' <question type="essay"> 423 <name> 424 <text>An essay</text> 425 </name> 426 <questiontext format="moodle_auto_format"> 427 <text>Write something.</text> 428 </questiontext> 429 <generalfeedback> 430 <text>I hope you wrote something interesting.</text> 431 </generalfeedback> 432 <defaultgrade>1</defaultgrade> 433 <penalty>0</penalty> 434 <hidden>0</hidden> 435 <responseformat>monospaced</responseformat> 436 <responserequired>0</responserequired> 437 <responsefieldlines>42</responsefieldlines> 438 <attachments>-1</attachments> 439 <attachmentsrequired>1</attachmentsrequired> 440 <graderinfo format="html"> 441 <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text> 442 </graderinfo> 443 <responsetemplate format="html"> 444 <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text> 445 </responsetemplate> 446 <tags> 447 <tag><text>tagEssay</text></tag> 448 <tag><text>tagEssay21</text></tag> 449 <tag><text>tagTest</text></tag> 450 </tags> 451 </question>'; 452 $xmldata = xmlize($xml); 453 454 $importer = new qformat_xml(); 455 $q = $importer->import_essay($xmldata['question']); 456 457 $expectedq = new stdClass(); 458 $expectedq->qtype = 'essay'; 459 $expectedq->name = 'An essay'; 460 $expectedq->questiontext = 'Write something.'; 461 $expectedq->questiontextformat = FORMAT_MOODLE; 462 $expectedq->generalfeedback = 'I hope you wrote something interesting.'; 463 $expectedq->defaultmark = 1; 464 $expectedq->length = 1; 465 $expectedq->penalty = 0; 466 $expectedq->responseformat = 'monospaced'; 467 $expectedq->responserequired = 0; 468 $expectedq->responsefieldlines = 42; 469 $expectedq->attachments = -1; 470 $expectedq->attachmentsrequired = 1; 471 $expectedq->filetypeslist = null; 472 $expectedq->graderinfo['text'] = '<p>Grade <b>generously</b>!</p>'; 473 $expectedq->graderinfo['format'] = FORMAT_HTML; 474 $expectedq->responsetemplate['text'] = '<p>Here is something <b>really</b> interesting.</p>'; 475 $expectedq->responsetemplate['format'] = FORMAT_HTML; 476 $expectedq->tags = array('tagEssay', 'tagEssay21', 'tagTest'); 477 478 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 479 } 480 481 public function test_export_essay() { 482 $qdata = new stdClass(); 483 $qdata->id = 123; 484 $qdata->contextid = \context_system::instance()->id; 485 $qdata->qtype = 'essay'; 486 $qdata->name = 'An essay'; 487 $qdata->questiontext = 'Write something.'; 488 $qdata->questiontextformat = FORMAT_MOODLE; 489 $qdata->generalfeedback = 'I hope you wrote something interesting.'; 490 $qdata->generalfeedbackformat = FORMAT_MOODLE; 491 $qdata->defaultmark = 1; 492 $qdata->length = 1; 493 $qdata->penalty = 0; 494 $qdata->hidden = 0; 495 $qdata->idnumber = null; 496 $qdata->options = new stdClass(); 497 $qdata->options->id = 456; 498 $qdata->options->questionid = 123; 499 $qdata->options->responseformat = 'monospaced'; 500 $qdata->options->responserequired = 0; 501 $qdata->options->responsefieldlines = 42; 502 $qdata->options->attachments = -1; 503 $qdata->options->attachmentsrequired = 1; 504 $qdata->options->graderinfo = '<p>Grade <b>generously</b>!</p>'; 505 $qdata->options->graderinfoformat = FORMAT_HTML; 506 $qdata->options->responsetemplate = '<p>Here is something <b>really</b> interesting.</p>'; 507 $qdata->options->responsetemplateformat = FORMAT_HTML; 508 $qdata->options->filetypeslist = '.pdf,.zip.,.docx'; 509 $exporter = new qformat_xml(); 510 $xml = $exporter->writequestion($qdata); 511 512 $expectedxml = '<!-- question: 123 --> 513 <question type="essay"> 514 <name> 515 <text>An essay</text> 516 </name> 517 <questiontext format="moodle_auto_format"> 518 <text>Write something.</text> 519 </questiontext> 520 <generalfeedback format="moodle_auto_format"> 521 <text>I hope you wrote something interesting.</text> 522 </generalfeedback> 523 <defaultgrade>1</defaultgrade> 524 <penalty>0</penalty> 525 <hidden>0</hidden> 526 <idnumber></idnumber> 527 <responseformat>monospaced</responseformat> 528 <responserequired>0</responserequired> 529 <responsefieldlines>42</responsefieldlines> 530 <attachments>-1</attachments> 531 <attachmentsrequired>1</attachmentsrequired> 532 <filetypeslist>.pdf,.zip.,.docx</filetypeslist> 533 <graderinfo format="html"> 534 <text><![CDATA[<p>Grade <b>generously</b>!</p>]]></text> 535 </graderinfo> 536 <responsetemplate format="html"> 537 <text><![CDATA[<p>Here is something <b>really</b> interesting.</p>]]></text> 538 </responsetemplate> 539 </question> 540 '; 541 542 $this->assert_same_xml($expectedxml, $xml); 543 } 544 545 public function test_import_match_19() { 546 $xml = ' <question type="matching"> 547 <name> 548 <text>Matching question</text> 549 </name> 550 <questiontext format="html"> 551 <text>Match the upper and lower case letters.</text> 552 </questiontext> 553 <generalfeedback> 554 <text>The answer is A -> a, B -> b and C -> c.</text> 555 </generalfeedback> 556 <defaultgrade>1</defaultgrade> 557 <penalty>0.3333333</penalty> 558 <hidden>0</hidden> 559 <shuffleanswers>false</shuffleanswers> 560 <correctfeedback> 561 <text>Well done.</text> 562 </correctfeedback> 563 <partiallycorrectfeedback> 564 <text>Not entirely.</text> 565 </partiallycorrectfeedback> 566 <incorrectfeedback> 567 <text>Completely wrong!</text> 568 </incorrectfeedback> 569 <subquestion> 570 <text>A</text> 571 <answer> 572 <text>a</text> 573 </answer> 574 </subquestion> 575 <subquestion> 576 <text>B</text> 577 <answer> 578 <text>b</text> 579 </answer> 580 </subquestion> 581 <subquestion> 582 <text>C</text> 583 <answer> 584 <text>c</text> 585 </answer> 586 </subquestion> 587 <subquestion> 588 <text></text> 589 <answer> 590 <text>d</text> 591 </answer> 592 </subquestion> 593 <hint> 594 <text>Hint 1</text> 595 <shownumcorrect /> 596 </hint> 597 <hint> 598 <text></text> 599 <shownumcorrect /> 600 <clearwrong /> 601 </hint> 602 <tags> 603 <tag><text>tagMatching</text></tag> 604 <tag><text>tagTest</text></tag> 605 </tags> 606 </question>'; 607 $xmldata = xmlize($xml); 608 609 $importer = new qformat_xml(); 610 $q = $importer->import_match($xmldata['question']); 611 612 $expectedq = new stdClass(); 613 $expectedq->qtype = 'match'; 614 $expectedq->name = 'Matching question'; 615 $expectedq->questiontext = 'Match the upper and lower case letters.'; 616 $expectedq->questiontextformat = FORMAT_HTML; 617 $expectedq->correctfeedback = array('text' => 'Well done.', 618 'format' => FORMAT_HTML); 619 $expectedq->partiallycorrectfeedback = array('text' => 'Not entirely.', 620 'format' => FORMAT_HTML); 621 $expectedq->shownumcorrect = false; 622 $expectedq->incorrectfeedback = array('text' => 'Completely wrong!', 623 'format' => FORMAT_HTML); 624 $expectedq->generalfeedback = 'The answer is A -> a, B -> b and C -> c.'; 625 $expectedq->generalfeedbackformat = FORMAT_HTML; 626 $expectedq->defaultmark = 1; 627 $expectedq->length = 1; 628 $expectedq->penalty = 0.3333333; 629 $expectedq->shuffleanswers = 0; 630 $expectedq->subquestions = array( 631 array('text' => 'A', 'format' => FORMAT_HTML), 632 array('text' => 'B', 'format' => FORMAT_HTML), 633 array('text' => 'C', 'format' => FORMAT_HTML), 634 array('text' => '', 'format' => FORMAT_HTML)); 635 $expectedq->subanswers = array('a', 'b', 'c', 'd'); 636 $expectedq->hint = array( 637 array('text' => 'Hint 1', 'format' => FORMAT_HTML), 638 array('text' => '', 'format' => FORMAT_HTML), 639 ); 640 $expectedq->hintshownumcorrect = array(true, true); 641 $expectedq->hintclearwrong = array(false, true); 642 $expectedq->tags = array('tagMatching', 'tagTest'); 643 644 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 645 } 646 647 public function test_export_match() { 648 $qdata = new stdClass(); 649 $qdata->id = 123; 650 $qdata->contextid = \context_system::instance()->id; 651 $qdata->qtype = 'match'; 652 $qdata->name = 'Matching question'; 653 $qdata->questiontext = 'Match the upper and lower case letters.'; 654 $qdata->questiontextformat = FORMAT_HTML; 655 $qdata->generalfeedback = 'The answer is A -> a, B -> b and C -> c.'; 656 $qdata->generalfeedbackformat = FORMAT_HTML; 657 $qdata->defaultmark = 1; 658 $qdata->length = 1; 659 $qdata->penalty = 0.3333333; 660 $qdata->hidden = 0; 661 $qdata->idnumber = null; 662 663 $qdata->options = new stdClass(); 664 $qdata->options->shuffleanswers = 1; 665 $qdata->options->correctfeedback = 'Well done.'; 666 $qdata->options->correctfeedbackformat = FORMAT_HTML; 667 $qdata->options->partiallycorrectfeedback = 'Not entirely.'; 668 $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML; 669 $qdata->options->shownumcorrect = false; 670 $qdata->options->incorrectfeedback = 'Completely wrong!'; 671 $qdata->options->incorrectfeedbackformat = FORMAT_HTML; 672 673 $subq1 = new stdClass(); 674 $subq1->id = -4; 675 $subq1->questiontext = 'A'; 676 $subq1->questiontextformat = FORMAT_HTML; 677 $subq1->answertext = 'a'; 678 679 $subq2 = new stdClass(); 680 $subq2->id = -3; 681 $subq2->questiontext = 'B'; 682 $subq2->questiontextformat = FORMAT_HTML; 683 $subq2->answertext = 'b'; 684 685 $subq3 = new stdClass(); 686 $subq3->id = -2; 687 $subq3->questiontext = 'C'; 688 $subq3->questiontextformat = FORMAT_HTML; 689 $subq3->answertext = 'c'; 690 691 $subq4 = new stdClass(); 692 $subq4->id = -1; 693 $subq4->questiontext = ''; 694 $subq4->questiontextformat = FORMAT_HTML; 695 $subq4->answertext = 'd'; 696 697 $qdata->options->subquestions = array( 698 $subq1, $subq2, $subq3, $subq4); 699 700 $qdata->hints = array( 701 new question_hint_with_parts(0, 'Hint 1', FORMAT_HTML, true, false), 702 new question_hint_with_parts(0, '', FORMAT_HTML, true, true), 703 ); 704 705 $exporter = new qformat_xml(); 706 $xml = $exporter->writequestion($qdata); 707 708 $expectedxml = '<!-- question: 123 --> 709 <question type="matching"> 710 <name> 711 <text>Matching question</text> 712 </name> 713 <questiontext format="html"> 714 <text>Match the upper and lower case letters.</text> 715 </questiontext> 716 <generalfeedback format="html"> 717 <text><![CDATA[The answer is A -> a, B -> b and C -> c.]]></text> 718 </generalfeedback> 719 <defaultgrade>1</defaultgrade> 720 <penalty>0.3333333</penalty> 721 <hidden>0</hidden> 722 <idnumber></idnumber> 723 <shuffleanswers>true</shuffleanswers> 724 <correctfeedback format="html"> 725 <text>Well done.</text> 726 </correctfeedback> 727 <partiallycorrectfeedback format="html"> 728 <text>Not entirely.</text> 729 </partiallycorrectfeedback> 730 <incorrectfeedback format="html"> 731 <text>Completely wrong!</text> 732 </incorrectfeedback> 733 <subquestion format="html"> 734 <text>A</text> 735 <answer> 736 <text>a</text> 737 </answer> 738 </subquestion> 739 <subquestion format="html"> 740 <text>B</text> 741 <answer> 742 <text>b</text> 743 </answer> 744 </subquestion> 745 <subquestion format="html"> 746 <text>C</text> 747 <answer> 748 <text>c</text> 749 </answer> 750 </subquestion> 751 <subquestion format="html"> 752 <text></text> 753 <answer> 754 <text>d</text> 755 </answer> 756 </subquestion> 757 <hint format="html"> 758 <text>Hint 1</text> 759 <shownumcorrect/> 760 </hint> 761 <hint format="html"> 762 <text></text> 763 <shownumcorrect/> 764 <clearwrong/> 765 </hint> 766 </question> 767 '; 768 769 $this->assert_same_xml($expectedxml, $xml); 770 } 771 772 public function test_import_multichoice_19() { 773 $xml = ' <question type="multichoice"> 774 <name> 775 <text>Multiple choice question</text> 776 </name> 777 <questiontext format="html"> 778 <text>Which are the even numbers?</text> 779 </questiontext> 780 <generalfeedback> 781 <text>The even numbers are 2 and 4.</text> 782 </generalfeedback> 783 <defaultgrade>2</defaultgrade> 784 <penalty>0.3333333</penalty> 785 <hidden>0</hidden> 786 <single>false</single> 787 <shuffleanswers>false</shuffleanswers> 788 <answernumbering>abc</answernumbering> 789 <correctfeedback> 790 <text><![CDATA[<p>Your answer is correct.</p>]]></text> 791 </correctfeedback> 792 <partiallycorrectfeedback> 793 <text><![CDATA[<p>Your answer is partially correct.</p>]]></text> 794 </partiallycorrectfeedback> 795 <incorrectfeedback> 796 <text><![CDATA[<p>Your answer is incorrect.</p>]]></text> 797 </incorrectfeedback> 798 <shownumcorrect/> 799 <answer fraction="0"> 800 <text>1</text> 801 <feedback> 802 <text></text> 803 </feedback> 804 </answer> 805 <answer fraction="100"> 806 <text>2</text> 807 <feedback> 808 <text></text> 809 </feedback> 810 </answer> 811 <answer fraction="0"> 812 <text>3</text> 813 <feedback> 814 <text></text> 815 </feedback> 816 </answer> 817 <answer fraction="100"> 818 <text>4</text> 819 <feedback> 820 <text></text> 821 </feedback> 822 </answer> 823 <hint> 824 <text>Hint 1.</text> 825 </hint> 826 <hint> 827 <text>Hint 2.</text> 828 </hint> 829 </question>'; 830 $xmldata = xmlize($xml); 831 832 $importer = new qformat_xml(); 833 $q = $importer->import_multichoice($xmldata['question']); 834 835 $expectedq = new stdClass(); 836 $expectedq->qtype = 'multichoice'; 837 $expectedq->name = 'Multiple choice question'; 838 $expectedq->questiontext = 'Which are the even numbers?'; 839 $expectedq->questiontextformat = FORMAT_HTML; 840 $expectedq->correctfeedback = array( 841 'text' => '<p>Your answer is correct.</p>', 842 'format' => FORMAT_HTML); 843 $expectedq->shownumcorrect = false; 844 $expectedq->partiallycorrectfeedback = array( 845 'text' => '<p>Your answer is partially correct.</p>', 846 'format' => FORMAT_HTML); 847 $expectedq->shownumcorrect = true; 848 $expectedq->incorrectfeedback = array( 849 'text' => '<p>Your answer is incorrect.</p>', 850 'format' => FORMAT_HTML); 851 $expectedq->generalfeedback = 'The even numbers are 2 and 4.'; 852 $expectedq->defaultmark = 2; 853 $expectedq->length = 1; 854 $expectedq->penalty = 0.3333333; 855 $expectedq->shuffleanswers = 0; 856 $expectedq->single = false; 857 858 $expectedq->answer = array( 859 array('text' => '1', 'format' => FORMAT_HTML), 860 array('text' => '2', 'format' => FORMAT_HTML), 861 array('text' => '3', 'format' => FORMAT_HTML), 862 array('text' => '4', 'format' => FORMAT_HTML)); 863 $expectedq->fraction = array(0, 1, 0, 1); 864 $expectedq->feedback = array( 865 array('text' => '', 'format' => FORMAT_HTML), 866 array('text' => '', 'format' => FORMAT_HTML), 867 array('text' => '', 'format' => FORMAT_HTML), 868 array('text' => '', 'format' => FORMAT_HTML)); 869 870 $expectedq->hint = array( 871 array('text' => 'Hint 1.', 'format' => FORMAT_HTML), 872 array('text' => 'Hint 2.', 'format' => FORMAT_HTML), 873 ); 874 $expectedq->hintshownumcorrect = array(false, false); 875 $expectedq->hintclearwrong = array(false, false); 876 877 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 878 } 879 880 public function test_export_multichoice() { 881 $qdata = new stdClass(); 882 $qdata->id = 123; 883 $qdata->contextid = \context_system::instance()->id; 884 $qdata->qtype = 'multichoice'; 885 $qdata->name = 'Multiple choice question'; 886 $qdata->questiontext = 'Which are the even numbers?'; 887 $qdata->questiontextformat = FORMAT_HTML; 888 $qdata->generalfeedback = 'The even numbers are 2 and 4.'; 889 $qdata->generalfeedbackformat = FORMAT_HTML; 890 $qdata->defaultmark = 2; 891 $qdata->length = 1; 892 $qdata->penalty = 0.3333333; 893 $qdata->hidden = 0; 894 $qdata->idnumber = null; 895 896 $qdata->options = new stdClass(); 897 $qdata->options->single = 0; 898 $qdata->options->shuffleanswers = 0; 899 $qdata->options->answernumbering = 'abc'; 900 $qdata->options->showstandardinstruction = 0; 901 $qdata->options->correctfeedback = '<p>Your answer is correct.</p>'; 902 $qdata->options->correctfeedbackformat = FORMAT_HTML; 903 $qdata->options->partiallycorrectfeedback = '<p>Your answer is partially correct.</p>'; 904 $qdata->options->partiallycorrectfeedbackformat = FORMAT_HTML; 905 $qdata->options->shownumcorrect = 1; 906 $qdata->options->incorrectfeedback = '<p>Your answer is incorrect.</p>'; 907 $qdata->options->incorrectfeedbackformat = FORMAT_HTML; 908 909 $qdata->options->answers = array( 910 13 => new question_answer(13, '1', 0, '', FORMAT_HTML), 911 14 => new question_answer(14, '2', 1, '', FORMAT_HTML), 912 15 => new question_answer(15, '3', 0, '', FORMAT_HTML), 913 16 => new question_answer(16, '4', 1, '', FORMAT_HTML), 914 ); 915 916 $qdata->hints = array( 917 new question_hint_with_parts(0, 'Hint 1.', FORMAT_HTML, false, false), 918 new question_hint_with_parts(0, 'Hint 2.', FORMAT_HTML, false, false), 919 ); 920 921 $exporter = new qformat_xml(); 922 $xml = $exporter->writequestion($qdata); 923 924 $expectedxml = '<!-- question: 123 --> 925 <question type="multichoice"> 926 <name> 927 <text>Multiple choice question</text> 928 </name> 929 <questiontext format="html"> 930 <text>Which are the even numbers?</text> 931 </questiontext> 932 <generalfeedback format="html"> 933 <text>The even numbers are 2 and 4.</text> 934 </generalfeedback> 935 <defaultgrade>2</defaultgrade> 936 <penalty>0.3333333</penalty> 937 <hidden>0</hidden> 938 <idnumber></idnumber> 939 <single>false</single> 940 <shuffleanswers>false</shuffleanswers> 941 <answernumbering>abc</answernumbering> 942 <showstandardinstruction>0</showstandardinstruction> 943 <correctfeedback format="html"> 944 <text><![CDATA[<p>Your answer is correct.</p>]]></text> 945 </correctfeedback> 946 <partiallycorrectfeedback format="html"> 947 <text><![CDATA[<p>Your answer is partially correct.</p>]]></text> 948 </partiallycorrectfeedback> 949 <incorrectfeedback format="html"> 950 <text><![CDATA[<p>Your answer is incorrect.</p>]]></text> 951 </incorrectfeedback> 952 <shownumcorrect/> 953 <answer fraction="0" format="plain_text"> 954 <text>1</text> 955 <feedback format="html"> 956 <text></text> 957 </feedback> 958 </answer> 959 <answer fraction="100" format="plain_text"> 960 <text>2</text> 961 <feedback format="html"> 962 <text></text> 963 </feedback> 964 </answer> 965 <answer fraction="0" format="plain_text"> 966 <text>3</text> 967 <feedback format="html"> 968 <text></text> 969 </feedback> 970 </answer> 971 <answer fraction="100" format="plain_text"> 972 <text>4</text> 973 <feedback format="html"> 974 <text></text> 975 </feedback> 976 </answer> 977 <hint format="html"> 978 <text>Hint 1.</text> 979 </hint> 980 <hint format="html"> 981 <text>Hint 2.</text> 982 </hint> 983 </question> 984 '; 985 986 $this->assert_same_xml($expectedxml, $xml); 987 } 988 989 public function test_import_numerical_19() { 990 $xml = ' <question type="numerical"> 991 <name> 992 <text>Numerical question</text> 993 </name> 994 <questiontext format="html"> 995 <text>What is the answer?</text> 996 </questiontext> 997 <generalfeedback> 998 <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text> 999 </generalfeedback> 1000 <defaultgrade>1</defaultgrade> 1001 <penalty>0.1</penalty> 1002 <hidden>0</hidden> 1003 <answer fraction="100"> 1004 <text>42</text> 1005 <feedback> 1006 <text>Well done!</text> 1007 </feedback> 1008 <tolerance>0.001</tolerance> 1009 </answer> 1010 <answer fraction="0"> 1011 <text>13</text> 1012 <feedback> 1013 <text>What were you thinking?!</text> 1014 </feedback> 1015 <tolerance>1</tolerance> 1016 </answer> 1017 <answer fraction="0"> 1018 <text>*</text> 1019 <feedback> 1020 <text>Completely wrong.</text> 1021 </feedback> 1022 <tolerance></tolerance> 1023 </answer> 1024 </question>'; 1025 $xmldata = xmlize($xml); 1026 1027 $importer = new qformat_xml(); 1028 $q = $importer->import_numerical($xmldata['question']); 1029 1030 $expectedq = new stdClass(); 1031 $expectedq->qtype = 'numerical'; 1032 $expectedq->name = 'Numerical question'; 1033 $expectedq->questiontext = 'What is the answer?'; 1034 $expectedq->questiontextformat = FORMAT_HTML; 1035 $expectedq->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.'; 1036 $expectedq->generalfeedbackformat = FORMAT_HTML; 1037 $expectedq->defaultmark = 1; 1038 $expectedq->length = 1; 1039 $expectedq->penalty = 0.1; 1040 1041 $expectedq->answer = array('42', '13', '*'); 1042 $expectedq->fraction = array(1, 0, 0); 1043 $expectedq->feedback = array( 1044 array('text' => 'Well done!', 1045 'format' => FORMAT_HTML), 1046 array('text' => 'What were you thinking?!', 1047 'format' => FORMAT_HTML), 1048 array('text' => 'Completely wrong.', 1049 'format' => FORMAT_HTML)); 1050 $expectedq->tolerance = array(0.001, 1, 0); 1051 1052 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1053 } 1054 1055 public function test_export_numerical() { 1056 question_bank::load_question_definition_classes('numerical'); 1057 1058 $qdata = new stdClass(); 1059 $qdata->id = 123; 1060 $qdata->contextid = \context_system::instance()->id; 1061 $qdata->qtype = 'numerical'; 1062 $qdata->name = 'Numerical question'; 1063 $qdata->questiontext = 'What is the answer?'; 1064 $qdata->questiontextformat = FORMAT_HTML; 1065 $qdata->generalfeedback = 'General feedback: Think Hitch-hikers guide to the Galaxy.'; 1066 $qdata->generalfeedbackformat = FORMAT_HTML; 1067 $qdata->defaultmark = 1; 1068 $qdata->length = 1; 1069 $qdata->penalty = 0.1; 1070 $qdata->hidden = 0; 1071 $qdata->idnumber = null; 1072 1073 $qdata->options = new stdClass(); 1074 $qdata->options->answers = array( 1075 13 => new qtype_numerical_answer(13, '42', 1, 'Well done!', 1076 FORMAT_HTML, 0.001), 1077 14 => new qtype_numerical_answer(14, '13', 0, 'What were you thinking?!', 1078 FORMAT_HTML, 1), 1079 15 => new qtype_numerical_answer(15, '*', 0, 'Completely wrong.', 1080 FORMAT_HTML, ''), 1081 ); 1082 1083 $qdata->options->units = array(); 1084 1085 $exporter = new qformat_xml(); 1086 $xml = $exporter->writequestion($qdata); 1087 1088 $expectedxml = '<!-- question: 123 --> 1089 <question type="numerical"> 1090 <name> 1091 <text>Numerical question</text> 1092 </name> 1093 <questiontext format="html"> 1094 <text>What is the answer?</text> 1095 </questiontext> 1096 <generalfeedback format="html"> 1097 <text>General feedback: Think Hitch-hikers guide to the Galaxy.</text> 1098 </generalfeedback> 1099 <defaultgrade>1</defaultgrade> 1100 <penalty>0.1</penalty> 1101 <hidden>0</hidden> 1102 <idnumber></idnumber> 1103 <answer fraction="100" format="plain_text"> 1104 <text>42</text> 1105 <feedback format="html"> 1106 <text>Well done!</text> 1107 </feedback> 1108 <tolerance>0.001</tolerance> 1109 </answer> 1110 <answer fraction="0" format="plain_text"> 1111 <text>13</text> 1112 <feedback format="html"> 1113 <text>What were you thinking?!</text> 1114 </feedback> 1115 <tolerance>1</tolerance> 1116 </answer> 1117 <answer fraction="0" format="plain_text"> 1118 <text>*</text> 1119 <feedback format="html"> 1120 <text>Completely wrong.</text> 1121 </feedback> 1122 <tolerance>0</tolerance> 1123 </answer> 1124 </question> 1125 '; 1126 1127 $this->assert_same_xml($expectedxml, $xml); 1128 } 1129 1130 public function test_import_shortanswer_19() { 1131 $xml = ' <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> 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> 1148 <text>Well done!</text> 1149 </feedback> 1150 </answer> 1151 <answer fraction="0" format="plain_text"> 1152 <text>*</text> 1153 <feedback> 1154 <text>Doh!</text> 1155 </feedback> 1156 </answer> 1157 <hint> 1158 <text>Hint 1</text> 1159 </hint> 1160 <hint> 1161 <text>Hint 2</text> 1162 </hint> 1163 </question>'; 1164 $xmldata = xmlize($xml); 1165 1166 $importer = new qformat_xml(); 1167 $q = $importer->import_shortanswer($xmldata['question']); 1168 1169 $expectedq = new stdClass(); 1170 $expectedq->qtype = 'shortanswer'; 1171 $expectedq->name = 'Short answer question'; 1172 $expectedq->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.'; 1173 $expectedq->questiontextformat = FORMAT_HTML; 1174 $expectedq->generalfeedback = 'The answer is Beta.'; 1175 $expectedq->usecase = false; 1176 $expectedq->defaultmark = 1; 1177 $expectedq->length = 1; 1178 $expectedq->penalty = 0.3333333; 1179 1180 $expectedq->answer = array('Beta', '*'); 1181 $expectedq->fraction = array(1, 0); 1182 $expectedq->feedback = array( 1183 array('text' => 'Well done!', 'format' => FORMAT_HTML), 1184 array('text' => 'Doh!', 'format' => FORMAT_HTML)); 1185 1186 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1187 } 1188 1189 public function test_export_shortanswer() { 1190 $qdata = new stdClass(); 1191 $qdata->id = 123; 1192 $qdata->contextid = \context_system::instance()->id; 1193 $qdata->qtype = 'shortanswer'; 1194 $qdata->name = 'Short answer question'; 1195 $qdata->questiontext = 'Fill in the gap in this sequence: Alpha, ________, Gamma.'; 1196 $qdata->questiontextformat = FORMAT_HTML; 1197 $qdata->generalfeedback = 'The answer is Beta.'; 1198 $qdata->generalfeedbackformat = FORMAT_HTML; 1199 $qdata->defaultmark = 1; 1200 $qdata->length = 1; 1201 $qdata->penalty = 0.3333333; 1202 $qdata->hidden = 0; 1203 $qdata->idnumber = null; 1204 1205 $qdata->options = new stdClass(); 1206 $qdata->options->usecase = 0; 1207 1208 $qdata->options->answers = array( 1209 13 => new question_answer(13, 'Beta', 1, 'Well done!', FORMAT_HTML), 1210 14 => new question_answer(14, '*', 0, 'Doh!', FORMAT_HTML), 1211 ); 1212 1213 $qdata->hints = array( 1214 new question_hint(0, 'Hint 1', FORMAT_HTML), 1215 new question_hint(0, 'Hint 2', FORMAT_HTML), 1216 ); 1217 1218 $exporter = new qformat_xml(); 1219 $xml = $exporter->writequestion($qdata); 1220 1221 $expectedxml = '<!-- question: 123 --> 1222 <question type="shortanswer"> 1223 <name> 1224 <text>Short answer question</text> 1225 </name> 1226 <questiontext format="html"> 1227 <text>Fill in the gap in this sequence: Alpha, ________, Gamma.</text> 1228 </questiontext> 1229 <generalfeedback format="html"> 1230 <text>The answer is Beta.</text> 1231 </generalfeedback> 1232 <defaultgrade>1</defaultgrade> 1233 <penalty>0.3333333</penalty> 1234 <hidden>0</hidden> 1235 <idnumber></idnumber> 1236 <usecase>0</usecase> 1237 <answer fraction="100" format="plain_text"> 1238 <text>Beta</text> 1239 <feedback format="html"> 1240 <text>Well done!</text> 1241 </feedback> 1242 </answer> 1243 <answer fraction="0" format="plain_text"> 1244 <text>*</text> 1245 <feedback format="html"> 1246 <text>Doh!</text> 1247 </feedback> 1248 </answer> 1249 <hint format="html"> 1250 <text>Hint 1</text> 1251 </hint> 1252 <hint format="html"> 1253 <text>Hint 2</text> 1254 </hint> 1255 </question> 1256 '; 1257 1258 $this->assert_same_xml($expectedxml, $xml); 1259 } 1260 1261 public function test_import_truefalse_19() { 1262 $xml = ' <question type="truefalse"> 1263 <name> 1264 <text>True false question</text> 1265 </name> 1266 <questiontext format="html"> 1267 <text>The answer is true.</text> 1268 </questiontext> 1269 <generalfeedback> 1270 <text>General feedback: You should have chosen true.</text> 1271 </generalfeedback> 1272 <defaultgrade>1</defaultgrade> 1273 <penalty>1</penalty> 1274 <hidden>0</hidden> 1275 <answer fraction="100"> 1276 <text>true</text> 1277 <feedback> 1278 <text>Well done!</text> 1279 </feedback> 1280 </answer> 1281 <answer fraction="0"> 1282 <text>false</text> 1283 <feedback> 1284 <text>Doh!</text> 1285 </feedback> 1286 </answer> 1287 </question>'; 1288 $xmldata = xmlize($xml); 1289 1290 $importer = new qformat_xml(); 1291 $q = $importer->import_truefalse($xmldata['question']); 1292 1293 $expectedq = new stdClass(); 1294 $expectedq->qtype = 'truefalse'; 1295 $expectedq->name = 'True false question'; 1296 $expectedq->questiontext = 'The answer is true.'; 1297 $expectedq->questiontextformat = FORMAT_HTML; 1298 $expectedq->generalfeedback = 'General feedback: You should have chosen true.'; 1299 $expectedq->defaultmark = 1; 1300 $expectedq->length = 1; 1301 $expectedq->penalty = 1; 1302 1303 $expectedq->feedbacktrue = array('text' => 'Well done!', 1304 'format' => FORMAT_HTML); 1305 $expectedq->feedbackfalse = array('text' => 'Doh!', 1306 'format' => FORMAT_HTML); 1307 $expectedq->correctanswer = true; 1308 1309 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1310 } 1311 1312 public function test_import_truefalse_with_idnumber() { 1313 $xml = ' <question type="truefalse"> 1314 <name> 1315 <text>True false question</text> 1316 </name> 1317 <questiontext format="html"> 1318 <text>The answer is true.</text> 1319 </questiontext> 1320 <generalfeedback> 1321 <text>General feedback: You should have chosen true.</text> 1322 </generalfeedback> 1323 <defaultgrade>1</defaultgrade> 1324 <penalty>1</penalty> 1325 <hidden>0</hidden> 1326 <idnumber>TestIdNum1</idnumber> 1327 <answer fraction="100"> 1328 <text>true</text> 1329 <feedback> 1330 <text>Well done!</text> 1331 </feedback> 1332 </answer> 1333 <answer fraction="0"> 1334 <text>false</text> 1335 <feedback> 1336 <text>Doh!</text> 1337 </feedback> 1338 </answer> 1339 </question>'; 1340 $xmldata = xmlize($xml); 1341 1342 $importer = new qformat_xml(); 1343 $q = $importer->import_truefalse($xmldata['question']); 1344 1345 $expectedq = new stdClass(); 1346 $expectedq->qtype = 'truefalse'; 1347 $expectedq->name = 'True false question'; 1348 $expectedq->questiontext = 'The answer is true.'; 1349 $expectedq->questiontextformat = FORMAT_HTML; 1350 $expectedq->generalfeedback = 'General feedback: You should have chosen true.'; 1351 $expectedq->defaultmark = 1; 1352 $expectedq->length = 1; 1353 $expectedq->penalty = 1; 1354 $expectedq->idnumber = 'TestIdNum1'; 1355 1356 $expectedq->feedbacktrue = array('text' => 'Well done!', 1357 'format' => FORMAT_HTML); 1358 $expectedq->feedbackfalse = array('text' => 'Doh!', 1359 'format' => FORMAT_HTML); 1360 $expectedq->correctanswer = true; 1361 1362 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1363 } 1364 1365 public function test_export_truefalse() { 1366 $qdata = new stdClass(); 1367 $qdata->id = 12; 1368 $qdata->contextid = \context_system::instance()->id; 1369 $qdata->qtype = 'truefalse'; 1370 $qdata->name = 'True false question'; 1371 $qdata->questiontext = 'The answer is true.'; 1372 $qdata->questiontextformat = FORMAT_HTML; 1373 $qdata->generalfeedback = 'General feedback: You should have chosen true.'; 1374 $qdata->generalfeedbackformat = FORMAT_HTML; 1375 $qdata->defaultmark = 1; 1376 $qdata->length = 1; 1377 $qdata->penalty = 1; 1378 $qdata->hidden = 0; 1379 $qdata->idnumber = null; 1380 1381 $qdata->options = new stdClass(); 1382 $qdata->options->answers = array( 1383 1 => new question_answer(1, 'True', 1, 'Well done!', FORMAT_HTML), 1384 2 => new question_answer(2, 'False', 0, 'Doh!', FORMAT_HTML), 1385 ); 1386 $qdata->options->trueanswer = 1; 1387 $qdata->options->falseanswer = 2; 1388 1389 $exporter = new qformat_xml(); 1390 $xml = $exporter->writequestion($qdata); 1391 1392 $expectedxml = '<!-- question: 12 --> 1393 <question type="truefalse"> 1394 <name> 1395 <text>True false question</text> 1396 </name> 1397 <questiontext format="html"> 1398 <text>The answer is true.</text> 1399 </questiontext> 1400 <generalfeedback format="html"> 1401 <text>General feedback: You should have chosen true.</text> 1402 </generalfeedback> 1403 <defaultgrade>1</defaultgrade> 1404 <penalty>1</penalty> 1405 <hidden>0</hidden> 1406 <idnumber></idnumber> 1407 <answer fraction="100" format="plain_text"> 1408 <text>true</text> 1409 <feedback format="html"> 1410 <text>Well done!</text> 1411 </feedback> 1412 </answer> 1413 <answer fraction="0" format="plain_text"> 1414 <text>false</text> 1415 <feedback format="html"> 1416 <text>Doh!</text> 1417 </feedback> 1418 </answer> 1419 </question> 1420 '; 1421 1422 $this->assert_same_xml($expectedxml, $xml); 1423 } 1424 1425 public function test_export_truefalse_with_idnumber() { 1426 $qdata = new stdClass(); 1427 $qdata->id = 12; 1428 $qdata->contextid = \context_system::instance()->id; 1429 $qdata->qtype = 'truefalse'; 1430 $qdata->name = 'True false question'; 1431 $qdata->questiontext = 'The answer is true.'; 1432 $qdata->questiontextformat = FORMAT_HTML; 1433 $qdata->generalfeedback = 'General feedback: You should have chosen true.'; 1434 $qdata->generalfeedbackformat = FORMAT_HTML; 1435 $qdata->defaultmark = 1; 1436 $qdata->length = 1; 1437 $qdata->penalty = 1; 1438 $qdata->hidden = 0; 1439 $qdata->idnumber = 'TestIDNum2'; 1440 1441 $qdata->options = new stdClass(); 1442 $qdata->options->answers = array( 1443 1 => new question_answer(1, 'True', 1, 'Well done!', FORMAT_HTML), 1444 2 => new question_answer(2, 'False', 0, 'Doh!', FORMAT_HTML), 1445 ); 1446 $qdata->options->trueanswer = 1; 1447 $qdata->options->falseanswer = 2; 1448 1449 $exporter = new qformat_xml(); 1450 $xml = $exporter->writequestion($qdata); 1451 1452 $expectedxml = '<!-- question: 12 --> 1453 <question type="truefalse"> 1454 <name> 1455 <text>True false question</text> 1456 </name> 1457 <questiontext format="html"> 1458 <text>The answer is true.</text> 1459 </questiontext> 1460 <generalfeedback format="html"> 1461 <text>General feedback: You should have chosen true.</text> 1462 </generalfeedback> 1463 <defaultgrade>1</defaultgrade> 1464 <penalty>1</penalty> 1465 <hidden>0</hidden> 1466 <idnumber>TestIDNum2</idnumber> 1467 <answer fraction="100" format="plain_text"> 1468 <text>true</text> 1469 <feedback format="html"> 1470 <text>Well done!</text> 1471 </feedback> 1472 </answer> 1473 <answer fraction="0" format="plain_text"> 1474 <text>false</text> 1475 <feedback format="html"> 1476 <text>Doh!</text> 1477 </feedback> 1478 </answer> 1479 </question> 1480 '; 1481 1482 $this->assert_same_xml($expectedxml, $xml); 1483 } 1484 1485 public function test_import_multianswer() { 1486 $xml = ' <question type="cloze"> 1487 <name> 1488 <text>Simple multianswer</text> 1489 </name> 1490 <questiontext format="html"> 1491 <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> 1492 </questiontext> 1493 <generalfeedback format="html"> 1494 <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".]]></text> 1495 </generalfeedback> 1496 <penalty>0.5</penalty> 1497 <hidden>0</hidden> 1498 <hint format="html"> 1499 <text>Hint 1</text> 1500 </hint> 1501 <hint format="html"> 1502 <text>Hint 2</text> 1503 </hint> 1504 <tags> 1505 <tag><text>tagCloze</text></tag> 1506 <tag><text>tagTest</text></tag> 1507 </tags> 1508 </question> 1509 '; 1510 $xmldata = xmlize($xml); 1511 1512 $importer = new qformat_xml(); 1513 $q = $importer->import_multianswer($xmldata['question']); 1514 1515 // Annoyingly, import works in a weird way (it duplicates code, rather 1516 // than just calling save_question) so we cannot use 1517 // test_question_maker::get_question_form_data('multianswer', 'twosubq'). 1518 $expectedqa = new stdClass(); 1519 $expectedqa->name = 'Simple multianswer'; 1520 $expectedqa->qtype = 'multianswer'; 1521 $expectedqa->questiontext = 'Complete this opening line of verse: "The {#1} and the {#2} went to sea".'; 1522 $expectedqa->generalfeedback = 1523 'General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea".'; 1524 $expectedqa->defaultmark = 2; 1525 $expectedqa->penalty = 0.5; 1526 1527 $expectedqa->hint = array( 1528 array('text' => 'Hint 1', 'format' => FORMAT_HTML), 1529 array('text' => 'Hint 2', 'format' => FORMAT_HTML), 1530 ); 1531 1532 $sa = new stdClass(); 1533 1534 $sa->questiontext = array('text' => '{1:SHORTANSWER:Dog#Wrong, silly!~=Owl#Well done!~*#Wrong answer}', 1535 'format' => FORMAT_HTML, 'itemid' => null); 1536 $sa->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null); 1537 $sa->defaultmark = 1.0; 1538 $sa->qtype = 'shortanswer'; 1539 $sa->usecase = 0; 1540 1541 $sa->answer = array('Dog', 'Owl', '*'); 1542 $sa->fraction = array(0, 1, 0); 1543 $sa->feedback = array( 1544 array('text' => 'Wrong, silly!', 'format' => FORMAT_HTML, 'itemid' => null), 1545 array('text' => 'Well done!', 'format' => FORMAT_HTML, 'itemid' => null), 1546 array('text' => 'Wrong answer', 'format' => FORMAT_HTML, 'itemid' => null), 1547 ); 1548 1549 $mc = new stdClass(); 1550 1551 $mc->generalfeedback = ''; 1552 $mc->questiontext = array('text' => '{1:MULTICHOICE:Bow-wow#You seem to have a dog obsessions!~' . 1553 'Wiggly worm#Now you are just being ridiculous!~=Pussy-cat#Well done!}', 1554 'format' => FORMAT_HTML, 'itemid' => null); 1555 $mc->generalfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null); 1556 $mc->defaultmark = 1.0; 1557 $mc->qtype = 'multichoice'; 1558 1559 $mc->layout = 0; 1560 $mc->single = 1; 1561 $mc->shuffleanswers = 0; 1562 $mc->correctfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null); 1563 $mc->partiallycorrectfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null); 1564 $mc->incorrectfeedback = array('text' => '', 'format' => FORMAT_HTML, 'itemid' => null); 1565 $mc->answernumbering = 0; 1566 1567 $mc->answer = array( 1568 array('text' => 'Bow-wow', 'format' => FORMAT_HTML, 'itemid' => null), 1569 array('text' => 'Wiggly worm', 'format' => FORMAT_HTML, 'itemid' => null), 1570 array('text' => 'Pussy-cat', 'format' => FORMAT_HTML, 'itemid' => null), 1571 ); 1572 $mc->fraction = array(0, 0, 1); 1573 $mc->feedback = array( 1574 array('text' => 'You seem to have a dog obsessions!', 'format' => FORMAT_HTML, 'itemid' => null), 1575 array('text' => 'Now you are just being ridiculous!', 'format' => FORMAT_HTML, 'itemid' => null), 1576 array('text' => 'Well done!', 'format' => FORMAT_HTML, 'itemid' => null), 1577 ); 1578 1579 $expectedqa->options = new stdClass(); 1580 $expectedqa->options->questions = array( 1581 1 => $sa, 1582 2 => $mc, 1583 ); 1584 $expectedqa->tags = array('tagCloze', 'tagTest'); 1585 1586 $this->assertEquals($expectedqa->hint, $q->hint); 1587 $this->assertEquals($expectedqa->options->questions[1], $q->options->questions[1]); 1588 $this->assertEquals($expectedqa->options->questions[2], $q->options->questions[2]); 1589 $this->assert(new question_check_specified_fields_expectation($expectedqa), $q); 1590 } 1591 1592 public function test_export_multianswer() { 1593 $qdata = test_question_maker::get_question_data('multianswer', 'twosubq'); 1594 $qdata->contextid = \context_system::instance()->id; 1595 $exporter = new qformat_xml(); 1596 $xml = $exporter->writequestion($qdata); 1597 1598 $expectedxml = '<!-- question: 0 --> 1599 <question type="cloze"> 1600 <name> 1601 <text>Simple multianswer</text> 1602 </name> 1603 <questiontext format="html"> 1604 <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> 1605 </questiontext> 1606 <generalfeedback format="html"> 1607 <text><![CDATA[General feedback: It\'s from "The Owl and the Pussy-cat" by Lear: "The owl and the pussycat went to sea]]></text> 1608 </generalfeedback> 1609 <penalty>0.3333333</penalty> 1610 <hidden>0</hidden> 1611 <idnumber></idnumber> 1612 <hint format="html"> 1613 <text>Hint 1</text> 1614 </hint> 1615 <hint format="html"> 1616 <text>Hint 2</text> 1617 </hint> 1618 </question> 1619 '; 1620 1621 $this->assert_same_xml($expectedxml, $xml); 1622 } 1623 1624 public function test_export_multianswer_withdollars() { 1625 $qdata = test_question_maker::get_question_data('multianswer', 'dollarsigns'); 1626 $qdata->contextid = \context_system::instance()->id; 1627 $exporter = new qformat_xml(); 1628 $xml = $exporter->writequestion($qdata); 1629 1630 $expectedxml = '<!-- question: 0 --> 1631 <question type="cloze"> 1632 <name> 1633 <text>Multianswer with $s</text> 1634 </name> 1635 <questiontext format="html"> 1636 <text>Which is the right order? {1:MULTICHOICE:=y,y,$3~$3,y,y}</text> 1637 </questiontext> 1638 <generalfeedback format="html"> 1639 <text></text> 1640 </generalfeedback> 1641 <penalty>0.3333333</penalty> 1642 <hidden>0</hidden> 1643 <idnumber></idnumber> 1644 </question> 1645 '; 1646 1647 $this->assert_same_xml($expectedxml, $xml); 1648 } 1649 1650 public function test_import_files_as_draft() { 1651 $this->resetAfterTest(); 1652 $this->setAdminUser(); 1653 1654 $xml = <<<END 1655 <questiontext format="html"> 1656 <text><![CDATA[<p><a href="@@PLUGINFILE@@/moodle.txt">This text file</a> contains the word 'Moodle'.</p>]]></text> 1657 <file name="moodle.txt" encoding="base64">TW9vZGxl</file> 1658 </questiontext> 1659 END; 1660 1661 $textxml = xmlize($xml); 1662 $qo = new stdClass(); 1663 1664 $importer = new qformat_xml(); 1665 $draftitemid = $importer->import_files_as_draft($textxml['questiontext']['#']['file']); 1666 $files = file_get_drafarea_files($draftitemid); 1667 1668 $this->assertEquals(1, count($files->list)); 1669 1670 $file = $files->list[0]; 1671 $this->assertEquals('moodle.txt', $file->filename); 1672 $this->assertEquals('/', $file->filepath); 1673 $this->assertEquals(6, $file->size); 1674 } 1675 1676 public function test_import_truefalse_wih_files() { 1677 $this->resetAfterTest(); 1678 $this->setAdminUser(); 1679 1680 $xml = '<question type="truefalse"> 1681 <name> 1682 <text>truefalse</text> 1683 </name> 1684 <questiontext format="html"> 1685 <text><![CDATA[<p><a href="@@PLUGINFILE@@/myfolder/moodle.txt">This text file</a> contains the word Moodle.</p>]]></text> 1686 <file name="moodle.txt" path="/myfolder/" encoding="base64">TW9vZGxl</file> 1687 </questiontext> 1688 <generalfeedback format="html"> 1689 <text><![CDATA[<p>For further information, see the documentation about Moodle.</p>]]></text> 1690 </generalfeedback> 1691 <defaultgrade>1.0000000</defaultgrade> 1692 <penalty>1.0000000</penalty> 1693 <hidden>0</hidden> 1694 <answer fraction="100" format="moodle_auto_format"> 1695 <text>true</text> 1696 <feedback format="html"> 1697 <text></text> 1698 </feedback> 1699 </answer> 1700 <answer fraction="0" format="moodle_auto_format"> 1701 <text>false</text> 1702 <feedback format="html"> 1703 <text></text> 1704 </feedback> 1705 </answer> 1706 </question>'; 1707 $xmldata = xmlize($xml); 1708 1709 $importer = new qformat_xml(); 1710 $q = $importer->import_truefalse($xmldata['question']); 1711 1712 $draftitemid = $q->questiontextitemid; 1713 $files = file_get_drafarea_files($draftitemid, '/myfolder/'); 1714 1715 $this->assertEquals(1, count($files->list)); 1716 1717 $file = $files->list[0]; 1718 $this->assertEquals('moodle.txt', $file->filename); 1719 $this->assertEquals('/myfolder/', $file->filepath); 1720 $this->assertEquals(6, $file->size); 1721 } 1722 1723 public function test_create_dummy_question() { 1724 1725 $testobject = new mock_qformat_xml(); 1726 $categoryname = 'name1'; 1727 $categoryinfo = new stdClass(); 1728 $categoryinfo->info = 'info1'; 1729 $categoryinfo->infoformat = 'infoformat1'; 1730 $categoryinfo->idnumber = null; 1731 $dummyquestion = $testobject->mock_create_dummy_question_representing_category($categoryname, $categoryinfo); 1732 1733 $this->assertEquals('category', $dummyquestion->qtype); 1734 $this->assertEquals($categoryname, $dummyquestion->category); 1735 $this->assertEquals($categoryinfo->info, $dummyquestion->info); 1736 $this->assertEquals($categoryinfo->infoformat, $dummyquestion->infoformat); 1737 $this->assertEquals('Switch category to ' . $categoryname, $dummyquestion->name); 1738 $this->assertEquals(0, $dummyquestion->id); 1739 $this->assertEquals('', $dummyquestion->questiontextformat); 1740 $this->assertEquals(0, $dummyquestion->contextid); 1741 } 1742 } 1743 1744 /** 1745 * Class mock_qformat_xml exists only to enable testing of the create dummy question category. 1746 * @package qformat_xml 1747 * @copyright 2018 The Open University 1748 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 1749 */ 1750 class mock_qformat_xml extends qformat_xml { 1751 /** 1752 * Make public an otherwise protected function. 1753 * @param string $categoryname the name of the category 1754 * @param object $categoryinfo description of the category 1755 */ 1756 public function mock_create_dummy_question_representing_category(string $categoryname, $categoryinfo) { 1757 return $this->create_dummy_question_representing_category($categoryname, $categoryinfo); 1758 } 1759 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body