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