See Release Notes
Long Term Support Release
Differences Between: [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 GIFT format. 19 * 20 * @package qformat_gift 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.php'); 31 require_once($CFG->dirroot . '/question/format/gift/format.php'); 32 require_once($CFG->dirroot . '/question/engine/tests/helpers.php'); 33 34 35 /** 36 * Unit tests for the GIFT import/export format. 37 * 38 * @copyright 2010 The Open University 39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 40 */ 41 class qformat_gift_test extends question_testcase { 42 public function assert_same_gift($expectedtext, $text) { 43 $this->assertEquals(str_replace("\r\n", "\n", $expectedtext), 44 str_replace("\r\n", "\n", $text)); 45 } 46 47 public function test_import_essay() { 48 $gift = ' 49 // essay 50 ::Q8:: How are you? {}'; 51 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 52 53 $importer = new qformat_gift(); 54 $q = $importer->readquestion($lines); 55 56 $expectedq = (object) array( 57 'name' => 'Q8', 58 'questiontext' => 'How are you?', 59 'questiontextformat' => FORMAT_MOODLE, 60 'generalfeedback' => '', 61 'generalfeedbackformat' => FORMAT_MOODLE, 62 'qtype' => 'essay', 63 'defaultmark' => 1, 64 'penalty' => 0.3333333, 65 'length' => 1, 66 'responseformat' => 'editor', 67 'responsefieldlines' => 15, 68 'attachments' => 0, 69 'graderinfo' => array( 70 'text' => '', 71 'format' => FORMAT_HTML, 72 'files' => array()), 73 ); 74 75 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 76 } 77 78 public function test_export_essay() { 79 $qdata = (object) array( 80 'id' => 666 , 81 'name' => 'Q8', 82 'questiontext' => 'How are you?', 83 'questiontextformat' => FORMAT_MOODLE, 84 'generalfeedback' => '', 85 'generalfeedbackformat' => FORMAT_MOODLE, 86 'defaultmark' => 1, 87 'penalty' => 0.3333333, 88 'length' => 1, 89 'qtype' => 'essay', 90 'options' => (object) array( 91 'responseformat' => 'editor', 92 'responsefieldlines' => 15, 93 'attachments' => 0, 94 'graderinfo' => '', 95 'graderinfoformat' => FORMAT_HTML, 96 ), 97 ); 98 99 $exporter = new qformat_gift(); 100 $gift = $exporter->writequestion($qdata); 101 102 $expectedgift = "// question: 666 name: Q8 103 ::Q8::How are you?{} 104 105 "; 106 107 $this->assert_same_gift($expectedgift, $gift); 108 } 109 110 public function test_import_match() { 111 $gift = ' 112 // question: 2 name: Moodle activities 113 ::Moodle activities::[html]Match the <b>activity</b> to the description.{ 114 =[html]An activity supporting asynchronous discussions. -> Forum 115 =[moodle]A teacher asks a question and specifies a choice of multiple responses. -> Choice 116 =[plain]A bank of record entries which participants can add to. -> Database 117 =[markdown]A collection of web pages that anyone can add to or edit. -> Wiki 118 = -> Chat 119 }'; 120 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 121 122 $importer = new qformat_gift(); 123 $q = $importer->readquestion($lines); 124 125 $expectedq = (object) array( 126 'name' => 'Moodle activities', 127 'questiontext' => 'Match the <b>activity</b> to the description.', 128 'questiontextformat' => FORMAT_HTML, 129 'generalfeedback' => '', 130 'generalfeedbackformat' => FORMAT_HTML, 131 'qtype' => 'match', 132 'defaultmark' => 1, 133 'penalty' => 0.3333333, 134 'length' => 1, 135 'shuffleanswers' => '1', 136 'correctfeedback' => array( 137 'text' => '', 138 'format' => FORMAT_HTML, 139 'files' => array(), 140 ), 141 'partiallycorrectfeedback' => array( 142 'text' => '', 143 'format' => FORMAT_HTML, 144 'files' => array(), 145 ), 146 'incorrectfeedback' => array( 147 'text' => '', 148 'format' => FORMAT_HTML, 149 'files' => array(), 150 ), 151 'subquestions' => array( 152 0 => array( 153 'text' => 'An activity supporting asynchronous discussions.', 154 'format' => FORMAT_HTML, 155 'files' => array(), 156 ), 157 1 => array( 158 'text' => 'A teacher asks a question and specifies a choice of multiple responses.', 159 'format' => FORMAT_MOODLE, 160 'files' => array(), 161 ), 162 2 => array( 163 'text' => 'A bank of record entries which participants can add to.', 164 'format' => FORMAT_PLAIN, 165 'files' => array(), 166 ), 167 3 => array( 168 'text' => 'A collection of web pages that anyone can add to or edit.', 169 'format' => FORMAT_MARKDOWN, 170 'files' => array(), 171 ), 172 4 => array( 173 'text' => '', 174 'format' => FORMAT_HTML, 175 'files' => array(), 176 ), 177 ), 178 'subanswers' => array( 179 0 => 'Forum', 180 1 => 'Choice', 181 2 => 'Database', 182 3 => 'Wiki', 183 4 => 'Chat', 184 ), 185 ); 186 187 // Repeated test for better failure messages. 188 $this->assertEquals($expectedq->subquestions, $q->subquestions); 189 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 190 } 191 192 public function test_export_match() { 193 $qdata = (object) array( 194 'id' => 666 , 195 'name' => 'Moodle activities', 196 'questiontext' => 'Match the <b>activity</b> to the description.', 197 'questiontextformat' => FORMAT_HTML, 198 'generalfeedback' => '', 199 'generalfeedbackformat' => FORMAT_HTML, 200 'defaultmark' => 1, 201 'penalty' => 0.3333333, 202 'length' => 1, 203 'qtype' => 'match', 204 'options' => (object) array( 205 'id' => 123, 206 'question' => 666, 207 'shuffleanswers' => 1, 208 'subquestions' => array( 209 42 => (object) array( 210 'id' => 1234, 211 'code' => 12341234, 212 'question' => 666, 213 'questiontext' => '<div class="frog">An activity supporting asynchronous discussions.</div>', 214 'questiontextformat' => FORMAT_HTML, 215 'answertext' => 'Forum', 216 ), 217 43 => (object) array( 218 'id' => 1234, 219 'code' => 12341234, 220 'question' => 666, 221 'questiontext' => 'A teacher asks a question and specifies a choice of multiple responses.', 222 'questiontextformat' => FORMAT_MOODLE, 223 'answertext' => 'Choice', 224 ), 225 44 => (object) array( 226 'id' => 1234, 227 'code' => 12341234, 228 'question' => 666, 229 'questiontext' => 'A bank of record entries which participants can add to.', 230 'questiontextformat' => FORMAT_PLAIN, 231 'answertext' => 'Database', 232 ), 233 45 => (object) array( 234 'id' => 1234, 235 'code' => 12341234, 236 'question' => 666, 237 'questiontext' => 'A collection of web pages that anyone can add to or edit.', 238 'questiontextformat' => FORMAT_MARKDOWN, 239 'answertext' => 'Wiki', 240 ), 241 46 => (object) array( 242 'id' => 1234, 243 'code' => 12341234, 244 'question' => 666, 245 'questiontext' => '', 246 'questiontextformat' => FORMAT_MARKDOWN, 247 'answertext' => 'Chat', 248 ), 249 ), 250 ), 251 ); 252 253 $exporter = new qformat_gift(); 254 $gift = $exporter->writequestion($qdata); 255 256 $expectedgift = "// question: 666 name: Moodle activities 257 ::Moodle activities::[html]Match the <b>activity</b> to the description.{ 258 \t=<div class\\=\"frog\">An activity supporting asynchronous discussions.</div> -> Forum 259 \t=[moodle]A teacher asks a question and specifies a choice of multiple responses. -> Choice 260 \t=[plain]A bank of record entries which participants can add to. -> Database 261 \t=[markdown]A collection of web pages that anyone can add to or edit. -> Wiki 262 \t= -> Chat 263 } 264 265 "; 266 267 $this->assert_same_gift($expectedgift, $gift); 268 } 269 270 /** 271 * Test import of multichoice question in GIFT format 272 * 273 * @dataProvider numberingstyle_provider 274 * 275 * @param string $numberingstyle multichoice numbering style to set for qtype_multichoice 276 * 277 */ 278 public function test_import_multichoice($numberingstyle) { 279 $this->resetAfterTest(true); 280 281 set_config('answernumbering', $numberingstyle, 'qtype_multichoice'); 282 $gift = " 283 // multiple choice with specified feedback for right and wrong answers 284 ::Q2:: What's between orange and green in the spectrum? 285 { 286 =yellow # right; good! 287 ~red # [html]wrong, it's yellow 288 ~[plain]blue # wrong, it's yellow 289 }"; 290 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 291 292 $importer = new qformat_gift(); 293 $q = $importer->readquestion($lines); 294 295 $expectedq = (object) array( 296 'name' => 'Q2', 297 'questiontext' => "What's between orange and green in the spectrum?", 298 'questiontextformat' => FORMAT_MOODLE, 299 'generalfeedback' => '', 300 'generalfeedbackformat' => FORMAT_MOODLE, 301 'qtype' => 'multichoice', 302 'defaultmark' => 1, 303 'penalty' => 0.3333333, 304 'length' => 1, 305 'single' => 1, 306 'shuffleanswers' => '1', 307 'answernumbering' => $numberingstyle, 308 'correctfeedback' => array( 309 'text' => '', 310 'format' => FORMAT_MOODLE, 311 'files' => array(), 312 ), 313 'partiallycorrectfeedback' => array( 314 'text' => '', 315 'format' => FORMAT_MOODLE, 316 'files' => array(), 317 ), 318 'incorrectfeedback' => array( 319 'text' => '', 320 'format' => FORMAT_MOODLE, 321 'files' => array(), 322 ), 323 'answer' => array( 324 0 => array( 325 'text' => 'yellow', 326 'format' => FORMAT_MOODLE, 327 'files' => array(), 328 ), 329 1 => array( 330 'text' => 'red', 331 'format' => FORMAT_MOODLE, 332 'files' => array(), 333 ), 334 2 => array( 335 'text' => 'blue', 336 'format' => FORMAT_PLAIN, 337 'files' => array(), 338 ), 339 ), 340 'fraction' => array(1, 0, 0), 341 'feedback' => array( 342 0 => array( 343 'text' => 'right; good!', 344 'format' => FORMAT_MOODLE, 345 'files' => array(), 346 ), 347 1 => array( 348 'text' => "wrong, it's yellow", 349 'format' => FORMAT_HTML, 350 'files' => array(), 351 ), 352 2 => array( 353 'text' => "wrong, it's yellow", 354 'format' => FORMAT_MOODLE, 355 'files' => array(), 356 ), 357 ), 358 ); 359 360 // Repeated test for better failure messages. 361 $this->assertEquals($expectedq->answer, $q->answer); 362 $this->assertEquals($expectedq->feedback, $q->feedback); 363 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 364 } 365 366 /** 367 * Return a list of numbering styles (see question/type/multichoice/questiontype.php 368 * for valid choices) 369 * 370 * @return array Array of 1-element arrays of qtype_multichoice numbering styles 371 */ 372 public function numberingstyle_provider() { 373 return [ 374 ['abc'], 375 ['ABCD'], 376 ['123'], 377 ['iii'], 378 ['IIII'], 379 ['none'] 380 ]; 381 } 382 383 public function test_import_multichoice_multi() { 384 $gift = " 385 // multiple choice, multiple response with specified feedback for right and wrong answers 386 ::colours:: What's between orange and green in the spectrum? 387 { 388 ~%50%yellow # right; good! 389 ~%-100%red # [html]wrong 390 ~%50%off-beige # right; good! 391 ~%-100%[plain]blue # wrong 392 }"; 393 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 394 395 $importer = new qformat_gift(); 396 $q = $importer->readquestion($lines); 397 398 $expectedq = (object) array( 399 'name' => 'colours', 400 'questiontext' => "What's between orange and green in the spectrum?", 401 'questiontextformat' => FORMAT_MOODLE, 402 'generalfeedback' => '', 403 'generalfeedbackformat' => FORMAT_MOODLE, 404 'qtype' => 'multichoice', 405 'defaultmark' => 1, 406 'penalty' => 0.3333333, 407 'length' => 1, 408 'single' => 0, 409 'shuffleanswers' => '1', 410 'answernumbering' => 'abc', 411 'correctfeedback' => array( 412 'text' => '', 413 'format' => FORMAT_MOODLE, 414 'files' => array(), 415 ), 416 'partiallycorrectfeedback' => array( 417 'text' => '', 418 'format' => FORMAT_MOODLE, 419 'files' => array(), 420 ), 421 'incorrectfeedback' => array( 422 'text' => '', 423 'format' => FORMAT_MOODLE, 424 'files' => array(), 425 ), 426 'answer' => array( 427 0 => array( 428 'text' => 'yellow', 429 'format' => FORMAT_MOODLE, 430 'files' => array(), 431 ), 432 1 => array( 433 'text' => 'red', 434 'format' => FORMAT_MOODLE, 435 'files' => array(), 436 ), 437 2 => array( 438 'text' => 'off-beige', 439 'format' => FORMAT_MOODLE, 440 'files' => array(), 441 ), 442 3 => array( 443 'text' => 'blue', 444 'format' => FORMAT_PLAIN, 445 'files' => array(), 446 ), 447 ), 448 'fraction' => array(0.5, -1, 0.5, -1), 449 'feedback' => array( 450 0 => array( 451 'text' => 'right; good!', 452 'format' => FORMAT_MOODLE, 453 'files' => array(), 454 ), 455 1 => array( 456 'text' => "wrong", 457 'format' => FORMAT_HTML, 458 'files' => array(), 459 ), 460 2 => array( 461 'text' => "right; good!", 462 'format' => FORMAT_MOODLE, 463 'files' => array(), 464 ), 465 3 => array( 466 'text' => "wrong", 467 'format' => FORMAT_MOODLE, 468 'files' => array(), 469 ), 470 ), 471 ); 472 473 // Repeated test for better failure messages. 474 $this->assertEquals($expectedq->answer, $q->answer); 475 $this->assertEquals($expectedq->feedback, $q->feedback); 476 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 477 } 478 479 public function test_import_multichoice_multi_tricky() { 480 $gift = " 481 // multiple choice, multiple response with specified feedback for right and wrong answers 482 ::colours:: What's between orange and green in the spectrum? 483 { 484 ~%100%yellow # right; good! 485 ~%-50%red # wrong 486 ~%-50%blue # wrong 487 }"; 488 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 489 490 $importer = new qformat_gift(); 491 $q = $importer->readquestion($lines); 492 493 $expectedq = (object) array( 494 'name' => 'colours', 495 'questiontext' => "What's between orange and green in the spectrum?", 496 'questiontextformat' => FORMAT_MOODLE, 497 'generalfeedback' => '', 498 'generalfeedbackformat' => FORMAT_MOODLE, 499 'qtype' => 'multichoice', 500 'defaultmark' => 1, 501 'penalty' => 0.3333333, 502 'length' => 1, 503 'single' => 0, 504 'shuffleanswers' => '1', 505 'answernumbering' => 'abc', 506 'correctfeedback' => array( 507 'text' => '', 508 'format' => FORMAT_MOODLE, 509 'files' => array(), 510 ), 511 'partiallycorrectfeedback' => array( 512 'text' => '', 513 'format' => FORMAT_MOODLE, 514 'files' => array(), 515 ), 516 'incorrectfeedback' => array( 517 'text' => '', 518 'format' => FORMAT_MOODLE, 519 'files' => array(), 520 ), 521 'answer' => array( 522 0 => array( 523 'text' => 'yellow', 524 'format' => FORMAT_MOODLE, 525 'files' => array(), 526 ), 527 1 => array( 528 'text' => 'red', 529 'format' => FORMAT_MOODLE, 530 'files' => array(), 531 ), 532 2 => array( 533 'text' => 'blue', 534 'format' => FORMAT_MOODLE, 535 'files' => array(), 536 ), 537 ), 538 'fraction' => array(1, -0.5, -0.5), 539 'feedback' => array( 540 0 => array( 541 'text' => 'right; good!', 542 'format' => FORMAT_MOODLE, 543 'files' => array(), 544 ), 545 1 => array( 546 'text' => "wrong", 547 'format' => FORMAT_MOODLE, 548 'files' => array(), 549 ), 550 2 => array( 551 'text' => "wrong", 552 'format' => FORMAT_MOODLE, 553 'files' => array(), 554 ), 555 ), 556 ); 557 558 // Repeated test for better failure messages. 559 $this->assertEquals($expectedq->answer, $q->answer); 560 $this->assertEquals($expectedq->feedback, $q->feedback); 561 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 562 } 563 564 public function test_export_multichoice() { 565 $qdata = (object) array( 566 'id' => 666 , 567 'name' => 'Q8', 568 'questiontext' => "What's between orange and green in the spectrum?", 569 'questiontextformat' => FORMAT_MOODLE, 570 'generalfeedback' => '', 571 'generalfeedbackformat' => FORMAT_MOODLE, 572 'defaultmark' => 1, 573 'penalty' => 0.3333333, 574 'length' => 1, 575 'qtype' => 'multichoice', 576 'options' => (object) array( 577 'single' => 1, 578 'shuffleanswers' => '1', 579 'answernumbering' => 'abc', 580 'correctfeedback' => '', 581 'correctfeedbackformat' => FORMAT_MOODLE, 582 'partiallycorrectfeedback' => '', 583 'partiallycorrectfeedbackformat' => FORMAT_MOODLE, 584 'incorrectfeedback' => '', 585 'incorrectfeedbackformat' => FORMAT_MOODLE, 586 'answers' => array( 587 123 => (object) array( 588 'id' => 123, 589 'answer' => 'yellow', 590 'answerformat' => FORMAT_MOODLE, 591 'fraction' => 1, 592 'feedback' => 'right; good!', 593 'feedbackformat' => FORMAT_MOODLE, 594 ), 595 124 => (object) array( 596 'id' => 124, 597 'answer' => 'red', 598 'answerformat' => FORMAT_MOODLE, 599 'fraction' => 0, 600 'feedback' => "wrong, it's yellow", 601 'feedbackformat' => FORMAT_HTML, 602 ), 603 125 => (object) array( 604 'id' => 125, 605 'answer' => 'blue', 606 'answerformat' => FORMAT_PLAIN, 607 'fraction' => 0, 608 'feedback' => "wrong, it's yellow", 609 'feedbackformat' => FORMAT_MOODLE, 610 ), 611 ), 612 ), 613 ); 614 615 $exporter = new qformat_gift(); 616 $gift = $exporter->writequestion($qdata); 617 618 $expectedgift = "// question: 666 name: Q8 619 ::Q8::What's between orange and green in the spectrum?{ 620 \t=yellow#right; good! 621 \t~red#[html]wrong, it's yellow 622 \t~[plain]blue#wrong, it's yellow 623 } 624 625 "; 626 627 $this->assert_same_gift($expectedgift, $gift); 628 } 629 630 public function test_export_multichoice_multi_tricky() { 631 $qdata = (object) array( 632 'id' => 666 , 633 'name' => 'Q8', 634 'questiontext' => "What's between orange and green in the spectrum?", 635 'questiontextformat' => FORMAT_MOODLE, 636 'generalfeedback' => '', 637 'generalfeedbackformat' => FORMAT_MOODLE, 638 'defaultmark' => 1, 639 'penalty' => 0.3333333, 640 'length' => 1, 641 'qtype' => 'multichoice', 642 'options' => (object) array( 643 'single' => 0, 644 'shuffleanswers' => '1', 645 'answernumbering' => 'abc', 646 'correctfeedback' => '', 647 'correctfeedbackformat' => FORMAT_MOODLE, 648 'partiallycorrectfeedback' => '', 649 'partiallycorrectfeedbackformat' => FORMAT_MOODLE, 650 'incorrectfeedback' => '', 651 'incorrectfeedbackformat' => FORMAT_MOODLE, 652 'answers' => array( 653 123 => (object) array( 654 'id' => 123, 655 'answer' => 'yellow', 656 'answerformat' => FORMAT_MOODLE, 657 'fraction' => 1, 658 'feedback' => 'right; good!', 659 'feedbackformat' => FORMAT_MOODLE, 660 ), 661 124 => (object) array( 662 'id' => 124, 663 'answer' => 'red', 664 'answerformat' => FORMAT_MOODLE, 665 'fraction' => -0.5, 666 'feedback' => "wrong, it's yellow", 667 'feedbackformat' => FORMAT_MOODLE, 668 ), 669 125 => (object) array( 670 'id' => 125, 671 'answer' => 'blue', 672 'answerformat' => FORMAT_MOODLE, 673 'fraction' => -0.5, 674 'feedback' => "wrong, it's yellow", 675 'feedbackformat' => FORMAT_MOODLE, 676 ), 677 ), 678 ), 679 ); 680 681 $exporter = new qformat_gift(); 682 $gift = $exporter->writequestion($qdata); 683 684 $expectedgift = "// question: 666 name: Q8 685 ::Q8::What's between orange and green in the spectrum?{ 686 \t~%100%yellow#right; good! 687 \t~%-50%red#wrong, it's yellow 688 \t~%-50%blue#wrong, it's yellow 689 } 690 691 "; 692 693 $this->assert_same_gift($expectedgift, $gift); 694 } 695 696 public function test_import_numerical() { 697 $gift = " 698 // math range question 699 ::Q5:: What is a number from 1 to 5? {#3:2~#Completely wrong}"; 700 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 701 702 $importer = new qformat_gift(); 703 $q = $importer->readquestion($lines); 704 705 $expectedq = (object) array( 706 'name' => 'Q5', 707 'questiontext' => "What is a number from 1 to 5?", 708 'questiontextformat' => FORMAT_MOODLE, 709 'generalfeedback' => '', 710 'generalfeedbackformat' => FORMAT_MOODLE, 711 'qtype' => 'numerical', 712 'defaultmark' => 1, 713 'penalty' => 0.3333333, 714 'length' => 1, 715 'answer' => array( 716 '3', 717 '*', 718 ), 719 'fraction' => array(1, 0), 720 'feedback' => array( 721 0 => array( 722 'text' => '', 723 'format' => FORMAT_MOODLE, 724 'files' => array(), 725 ), 726 1 => array( 727 'text' => "Completely wrong", 728 'format' => FORMAT_MOODLE, 729 'files' => array(), 730 ), 731 ), 732 'tolerance' => array(2, 0), 733 ); 734 735 // Repeated test for better failure messages. 736 $this->assertEquals($expectedq->answer, $q->answer); 737 $this->assertEquals($expectedq->fraction, $q->fraction); 738 $this->assertEquals($expectedq->feedback, $q->feedback); 739 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 740 } 741 742 public function test_export_numerical() { 743 $qdata = (object) array( 744 'id' => 666 , 745 'name' => 'Q5', 746 'questiontext' => "What is a number from 1 to 5?", 747 'questiontextformat' => FORMAT_MOODLE, 748 'generalfeedback' => '', 749 'generalfeedbackformat' => FORMAT_MOODLE, 750 'defaultmark' => 1, 751 'penalty' => 1, 752 'length' => 1, 753 'qtype' => 'numerical', 754 'options' => (object) array( 755 'id' => 123, 756 'question' => 666, 757 'unitsleft' => 0, 758 'showunits' => 2, 759 'unitgradingtype' => 0, 760 'unitpenalty' => 0, 761 'answers' => array( 762 1 => (object) array( 763 'id' => 123, 764 'answer' => '3', 765 'answerformat' => 0, 766 'fraction' => 1, 767 'tolerance' => 2, 768 'feedback' => '', 769 'feedbackformat' => FORMAT_MOODLE, 770 ), 771 2 => (object) array( 772 'id' => 124, 773 'answer' => '*', 774 'answerformat' => 0, 775 'fraction' => 0, 776 'tolerance' => 0, 777 'feedback' => "Completely wrong", 778 'feedbackformat' => FORMAT_MOODLE, 779 ), 780 ), 781 ), 782 ); 783 784 $exporter = new qformat_gift(); 785 $gift = $exporter->writequestion($qdata); 786 787 $expectedgift = "// question: 666 name: Q5 788 ::Q5::What is a number from 1 to 5?{# 789 \t=%100%3:2# 790 \t~#Completely wrong 791 } 792 793 "; 794 795 $this->assert_same_gift($expectedgift, $gift); 796 } 797 798 public function test_import_shortanswer() { 799 $gift = " 800 // question: 666 name: Shortanswer 801 ::Shortanswer::Which is the best animal?{ 802 =Frog#Good! 803 =%50%Cat#What is it with Moodlers and cats? 804 =%0%*#Completely wrong 805 }"; 806 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 807 808 $importer = new qformat_gift(); 809 $q = $importer->readquestion($lines); 810 811 $expectedq = (object) array( 812 'name' => 'Shortanswer', 813 'questiontext' => "Which is the best animal?", 814 'questiontextformat' => FORMAT_MOODLE, 815 'generalfeedback' => '', 816 'generalfeedbackformat' => FORMAT_MOODLE, 817 'qtype' => 'shortanswer', 818 'defaultmark' => 1, 819 'penalty' => 0.3333333, 820 'length' => 1, 821 'answer' => array( 822 'Frog', 823 'Cat', 824 '*', 825 ), 826 'fraction' => array(1, 0.5, 0), 827 'feedback' => array( 828 0 => array( 829 'text' => 'Good!', 830 'format' => FORMAT_MOODLE, 831 'files' => array(), 832 ), 833 1 => array( 834 'text' => "What is it with Moodlers and cats?", 835 'format' => FORMAT_MOODLE, 836 'files' => array(), 837 ), 838 2 => array( 839 'text' => "Completely wrong", 840 'format' => FORMAT_MOODLE, 841 'files' => array(), 842 ), 843 ), 844 ); 845 846 // Repeated test for better failure messages. 847 $this->assertEquals($expectedq->answer, $q->answer); 848 $this->assertEquals($expectedq->fraction, $q->fraction); 849 $this->assertEquals($expectedq->feedback, $q->feedback); 850 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 851 } 852 853 public function test_import_shortanswer_with_general_feedback() { 854 $gift = " 855 // question: 666 name: Shortanswer 856 ::Shortanswer::Which is the best animal?{ 857 =Frog#Good! 858 =%50%Cat#What is it with Moodlers and cats? 859 =%0%*#Completely wrong 860 ####[html]Here is some general feedback! 861 }"; 862 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 863 864 $importer = new qformat_gift(); 865 $q = $importer->readquestion($lines); 866 867 $expectedq = (object) array( 868 'name' => 'Shortanswer', 869 'questiontext' => "Which is the best animal?", 870 'questiontextformat' => FORMAT_MOODLE, 871 'generalfeedback' => 'Here is some general feedback!', 872 'generalfeedbackformat' => FORMAT_HTML, 873 'qtype' => 'shortanswer', 874 'defaultmark' => 1, 875 'penalty' => 0.3333333, 876 'length' => 1, 877 'answer' => array( 878 'Frog', 879 'Cat', 880 '*', 881 ), 882 'fraction' => array(1, 0.5, 0), 883 'feedback' => array( 884 0 => array( 885 'text' => 'Good!', 886 'format' => FORMAT_MOODLE, 887 'files' => array(), 888 ), 889 1 => array( 890 'text' => "What is it with Moodlers and cats?", 891 'format' => FORMAT_MOODLE, 892 'files' => array(), 893 ), 894 2 => array( 895 'text' => "Completely wrong", 896 'format' => FORMAT_MOODLE, 897 'files' => array(), 898 ), 899 ), 900 ); 901 902 // Repeated test for better failure messages. 903 $this->assertEquals($expectedq->answer, $q->answer); 904 $this->assertEquals($expectedq->fraction, $q->fraction); 905 $this->assertEquals($expectedq->feedback, $q->feedback); 906 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 907 } 908 909 public function test_export_shortanswer() { 910 $qdata = (object) array( 911 'id' => 666 , 912 'name' => 'Shortanswer', 913 'questiontext' => "Which is the best animal?", 914 'questiontextformat' => FORMAT_MOODLE, 915 'generalfeedback' => '', 916 'generalfeedbackformat' => FORMAT_MOODLE, 917 'defaultmark' => 1, 918 'penalty' => 1, 919 'length' => 1, 920 'qtype' => 'shortanswer', 921 'options' => (object) array( 922 'id' => 123, 923 'questionid' => 666, 924 'usecase' => 1, 925 'answers' => array( 926 1 => (object) array( 927 'id' => 1, 928 'answer' => 'Frog', 929 'answerformat' => 0, 930 'fraction' => 1, 931 'feedback' => 'Good!', 932 'feedbackformat' => FORMAT_MOODLE, 933 ), 934 2 => (object) array( 935 'id' => 2, 936 'answer' => 'Cat', 937 'answerformat' => 0, 938 'fraction' => 0.5, 939 'feedback' => "What is it with Moodlers and cats?", 940 'feedbackformat' => FORMAT_MOODLE, 941 ), 942 3 => (object) array( 943 'id' => 3, 944 'answer' => '*', 945 'answerformat' => 0, 946 'fraction' => 0, 947 'feedback' => "Completely wrong", 948 'feedbackformat' => FORMAT_MOODLE, 949 ), 950 ), 951 ), 952 ); 953 954 $exporter = new qformat_gift(); 955 $gift = $exporter->writequestion($qdata); 956 957 $expectedgift = "// question: 666 name: Shortanswer 958 ::Shortanswer::Which is the best animal?{ 959 \t=%100%Frog#Good! 960 \t=%50%Cat#What is it with Moodlers and cats? 961 \t=%0%*#Completely wrong 962 } 963 964 "; 965 966 $this->assert_same_gift($expectedgift, $gift); 967 } 968 969 public function test_export_shortanswer_with_general_feedback() { 970 $qdata = (object) array( 971 'id' => 666 , 972 'name' => 'Shortanswer', 973 'questiontext' => "Which is the best animal?", 974 'questiontextformat' => FORMAT_MOODLE, 975 'generalfeedback' => 'Here is some general feedback!', 976 'generalfeedbackformat' => FORMAT_HTML, 977 'defaultmark' => 1, 978 'penalty' => 1, 979 'length' => 1, 980 'qtype' => 'shortanswer', 981 'options' => (object) array( 982 'id' => 123, 983 'questionid' => 666, 984 'usecase' => 1, 985 'answers' => array( 986 1 => (object) array( 987 'id' => 1, 988 'answer' => 'Frog', 989 'answerformat' => 0, 990 'fraction' => 1, 991 'feedback' => 'Good!', 992 'feedbackformat' => FORMAT_MOODLE, 993 ), 994 2 => (object) array( 995 'id' => 2, 996 'answer' => 'Cat', 997 'answerformat' => 0, 998 'fraction' => 0.5, 999 'feedback' => "What is it with Moodlers and cats?", 1000 'feedbackformat' => FORMAT_MOODLE, 1001 ), 1002 3 => (object) array( 1003 'id' => 3, 1004 'answer' => '*', 1005 'answerformat' => 0, 1006 'fraction' => 0, 1007 'feedback' => "Completely wrong", 1008 'feedbackformat' => FORMAT_MOODLE, 1009 ), 1010 ), 1011 ), 1012 ); 1013 1014 $exporter = new qformat_gift(); 1015 $gift = $exporter->writequestion($qdata); 1016 1017 $expectedgift = "// question: 666 name: Shortanswer 1018 ::Shortanswer::Which is the best animal?{ 1019 \t=%100%Frog#Good! 1020 \t=%50%Cat#What is it with Moodlers and cats? 1021 \t=%0%*#Completely wrong 1022 \t####[html]Here is some general feedback! 1023 } 1024 1025 "; 1026 1027 $this->assert_same_gift($expectedgift, $gift); 1028 } 1029 1030 public function test_import_truefalse() { 1031 $gift = " 1032 // true/false 1033 ::Q1:: 42 is the Absolute Answer to everything.{ 1034 FALSE#42 is the Ultimate Answer.#You gave the right answer.}"; 1035 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1036 1037 $importer = new qformat_gift(); 1038 $q = $importer->readquestion($lines); 1039 1040 $expectedq = (object) array( 1041 'name' => 'Q1', 1042 'questiontext' => "42 is the Absolute Answer to everything.", 1043 'questiontextformat' => FORMAT_MOODLE, 1044 'generalfeedback' => '', 1045 'generalfeedbackformat' => FORMAT_MOODLE, 1046 'qtype' => 'truefalse', 1047 'defaultmark' => 1, 1048 'penalty' => 1, 1049 'length' => 1, 1050 'correctanswer' => 0, 1051 'feedbacktrue' => array( 1052 'text' => '42 is the Ultimate Answer.', 1053 'format' => FORMAT_MOODLE, 1054 'files' => array(), 1055 ), 1056 'feedbackfalse' => array( 1057 'text' => 'You gave the right answer.', 1058 'format' => FORMAT_MOODLE, 1059 'files' => array(), 1060 ), 1061 ); 1062 1063 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1064 } 1065 1066 public function test_import_truefalse_true_answer1() { 1067 $gift = "// name 0-11 1068 ::2-08 TSL::TSL is blablabla.{T}"; 1069 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1070 1071 $importer = new qformat_gift(); 1072 $q = $importer->readquestion($lines); 1073 1074 $expectedq = (object) array( 1075 'name' => '2-08 TSL', 1076 'questiontext' => "TSL is blablabla.", 1077 'questiontextformat' => FORMAT_MOODLE, 1078 'generalfeedback' => '', 1079 'generalfeedbackformat' => FORMAT_MOODLE, 1080 'qtype' => 'truefalse', 1081 'defaultmark' => 1, 1082 'penalty' => 1, 1083 'length' => 1, 1084 'correctanswer' => 1, 1085 'feedbacktrue' => array( 1086 'text' => '', 1087 'format' => FORMAT_MOODLE, 1088 'files' => array(), 1089 ), 1090 'feedbackfalse' => array( 1091 'text' => '', 1092 'format' => FORMAT_MOODLE, 1093 'files' => array(), 1094 ), 1095 ); 1096 1097 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1098 } 1099 1100 public function test_import_truefalse_true_answer2() { 1101 $gift = "// name 0-11 1102 ::2-08 TSL::TSL is blablabla.{TRUE}"; 1103 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1104 1105 $importer = new qformat_gift(); 1106 $q = $importer->readquestion($lines); 1107 1108 $expectedq = (object) array( 1109 'name' => '2-08 TSL', 1110 'questiontext' => "TSL is blablabla.", 1111 'questiontextformat' => FORMAT_MOODLE, 1112 'generalfeedback' => '', 1113 'generalfeedbackformat' => FORMAT_MOODLE, 1114 'qtype' => 'truefalse', 1115 'defaultmark' => 1, 1116 'penalty' => 1, 1117 'length' => 1, 1118 'correctanswer' => 1, 1119 'feedbacktrue' => array( 1120 'text' => '', 1121 'format' => FORMAT_MOODLE, 1122 'files' => array(), 1123 ), 1124 'feedbackfalse' => array( 1125 'text' => '', 1126 'format' => FORMAT_MOODLE, 1127 'files' => array(), 1128 ), 1129 ); 1130 1131 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1132 } 1133 1134 public function test_export_truefalse() { 1135 $qdata = (object) array( 1136 'id' => 666 , 1137 'name' => 'Q1', 1138 'questiontext' => "42 is the Absolute Answer to everything.", 1139 'questiontextformat' => FORMAT_MOODLE, 1140 'generalfeedback' => '', 1141 'generalfeedbackformat' => FORMAT_MOODLE, 1142 'defaultmark' => 1, 1143 'penalty' => 1, 1144 'length' => 1, 1145 'qtype' => 'truefalse', 1146 'options' => (object) array( 1147 'id' => 123, 1148 'question' => 666, 1149 'trueanswer' => 1, 1150 'falseanswer' => 2, 1151 'answers' => array( 1152 1 => (object) array( 1153 'id' => 123, 1154 'answer' => 'True', 1155 'answerformat' => 0, 1156 'fraction' => 1, 1157 'feedback' => 'You gave the right answer.', 1158 'feedbackformat' => FORMAT_MOODLE, 1159 ), 1160 2 => (object) array( 1161 'id' => 124, 1162 'answer' => 'False', 1163 'answerformat' => 0, 1164 'fraction' => 0, 1165 'feedback' => "42 is the Ultimate Answer.", 1166 'feedbackformat' => FORMAT_HTML, 1167 ), 1168 ), 1169 ), 1170 ); 1171 1172 $exporter = new qformat_gift(); 1173 $gift = $exporter->writequestion($qdata); 1174 1175 $expectedgift = "// question: 666 name: Q1 1176 ::Q1::42 is the Absolute Answer to everything.{TRUE#[html]42 is the Ultimate Answer.#You gave the right answer.} 1177 1178 "; 1179 1180 $this->assert_same_gift($expectedgift, $gift); 1181 } 1182 1183 public function test_export_backslash() { 1184 // There was a bug (MDL-34171) where \\ was getting exported as \\, not 1185 // \\\\, and on import, \\ in converted to \. 1186 // We need \\\\ in the test code, because of PHPs string escaping rules. 1187 $qdata = (object) array( 1188 'id' => 666 , 1189 'name' => 'backslash', 1190 'questiontext' => 'A \\ B \\\\ C', 1191 'questiontextformat' => FORMAT_MOODLE, 1192 'generalfeedback' => '', 1193 'generalfeedbackformat' => FORMAT_MOODLE, 1194 'defaultmark' => 1, 1195 'penalty' => 0.3333333, 1196 'length' => 1, 1197 'qtype' => 'essay', 1198 'options' => (object) array( 1199 'responseformat' => 'editor', 1200 'responsefieldlines' => 15, 1201 'attachments' => 0, 1202 'graderinfo' => '', 1203 'graderinfoformat' => FORMAT_HTML, 1204 ), 1205 ); 1206 1207 $exporter = new qformat_gift(); 1208 $gift = $exporter->writequestion($qdata); 1209 1210 $expectedgift = "// question: 666 name: backslash 1211 ::backslash::A \\\\ B \\\\\\\\ C{} 1212 1213 "; 1214 1215 $this->assert_same_gift($expectedgift, $gift); 1216 } 1217 1218 public function test_import_backslash() { 1219 // There was a bug (MDL-34171) where \\ in the import was getting changed 1220 // to \. This test checks for that. 1221 // We need \\\\ in the test code, because of PHPs string escaping rules. 1222 $gift = ' 1223 // essay 1224 ::double backslash:: A \\\\ B \\\\\\\\ C{}'; 1225 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1226 1227 $importer = new qformat_gift(); 1228 $q = $importer->readquestion($lines); 1229 1230 $expectedq = (object) array( 1231 'name' => 'double backslash', 1232 'questiontext' => 'A \\ B \\\\ C', 1233 'questiontextformat' => FORMAT_MOODLE, 1234 'generalfeedback' => '', 1235 'generalfeedbackformat' => FORMAT_MOODLE, 1236 'qtype' => 'essay', 1237 'defaultmark' => 1, 1238 'penalty' => 0.3333333, 1239 'length' => 1, 1240 'responseformat' => 'editor', 1241 'responsefieldlines' => 15, 1242 'attachments' => 0, 1243 'graderinfo' => array( 1244 'text' => '', 1245 'format' => FORMAT_HTML, 1246 'files' => array()), 1247 ); 1248 1249 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1250 } 1251 1252 public function test_import_pre_content() { 1253 $gift = ' 1254 ::Q001::[html]<p>What would running the test method print?</p> 1255 <pre> 1256 public void test() \{ 1257 method1(); 1258 method2(); 1259 method3(); 1260 \} 1261 </pre> 1262 {}'; 1263 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1264 1265 $importer = new qformat_gift(); 1266 $q = $importer->readquestion($lines); 1267 1268 $expectedq = (object) array( 1269 'name' => 'Q001', 1270 'questiontext' => '<p>What would running the test method print?</p> 1271 <pre> 1272 public void test() { 1273 method1(); 1274 method2(); 1275 method3(); 1276 } 1277 </pre>', 1278 'questiontextformat' => FORMAT_HTML, 1279 'generalfeedback' => '', 1280 'generalfeedbackformat' => FORMAT_HTML, 1281 'qtype' => 'essay', 1282 'defaultmark' => 1, 1283 'penalty' => 0.3333333, 1284 'length' => 1, 1285 'responseformat' => 'editor', 1286 'responsefieldlines' => 15, 1287 'attachments' => 0, 1288 'graderinfo' => array( 1289 'text' => '', 1290 'format' => FORMAT_HTML, 1291 'files' => array()), 1292 ); 1293 1294 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1295 } 1296 1297 public function test_import_question_with_tags() { 1298 $gift = ' 1299 // This question is to test importing tags: [tag:tag] [tag:other-tag]. 1300 // And an idnumber: [id:myid]. 1301 ::Question name:: How are you? {}'; 1302 $lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift)); 1303 1304 $importer = new qformat_gift(); 1305 $q = $importer->readquestion($lines); 1306 1307 $expectedq = (object) array( 1308 'name' => 'Question name', 1309 'questiontext' => 'How are you?', 1310 'questiontextformat' => FORMAT_MOODLE, 1311 'generalfeedback' => '', 1312 'generalfeedbackformat' => FORMAT_MOODLE, 1313 'qtype' => 'essay', 1314 'defaultmark' => 1, 1315 'penalty' => 0.3333333, 1316 'length' => 1, 1317 'responseformat' => 'editor', 1318 'responsefieldlines' => 15, 1319 'attachments' => 0, 1320 'graderinfo' => array( 1321 'text' => '', 1322 'format' => FORMAT_HTML, 1323 'files' => array()), 1324 'tags' => ['tag', 'other-tag'], 1325 'idnumber' => 'myid', 1326 ); 1327 1328 $this->assert(new question_check_specified_fields_expectation($expectedq), $q); 1329 } 1330 1331 /** 1332 * Data provider for test_extract_idnumber_and_tags_from_comment. 1333 * 1334 * @return array the test cases. 1335 */ 1336 public function extract_idnumber_and_tags_from_comment_testcases() { 1337 return [ 1338 'blank comment' => ['', [], ''], 1339 'nothing in comment' => ['', [], '// A basic comment.'], 1340 'idnumber only' => ['frog', [], '// A comment with [id:frog] <-- an idnumber.'], 1341 'tags only' => ['', ['frog', 'toad'], '// Look tags: [tag:frog] [tag:toad].'], 1342 'everything' => ['four', ['add', 'basic'], '// [tag:add] [tag:basic] [id:four]'], 1343 'everything mixed up' => ['four', ['basic', 'add'], 1344 "// [tag: basic] Here is \n// a [id: four ] que[tag:add ]stion."], 1345 'split over line' => ['', [], "// Ceci n\'est pas une [tag:\n\\ frog]."], 1346 'escape ] idnumber' => ['i]d', [], '// [id:i\]d].'], 1347 'escape ] tag' => ['', ['t]ag'], '// [tag:t\]ag].'], 1348 ]; 1349 } 1350 1351 /** 1352 * Test extract_idnumber_and_tags_from_comment. 1353 * 1354 * @dataProvider extract_idnumber_and_tags_from_comment_testcases 1355 * @param string $expectedidnumber the expected idnumber. 1356 * @param array $expectedtags the expected tags. 1357 * @param string $comment the comment to parse. 1358 */ 1359 public function test_extract_idnumber_and_tags_from_comment( 1360 string $expectedidnumber, array $expectedtags, string $comment) { 1361 $importer = new qformat_gift(); 1362 1363 list($idnumber, $tags) = $importer->extract_idnumber_and_tags_from_comment($comment); 1364 $this->assertSame($expectedidnumber, $idnumber); 1365 $this->assertSame($expectedtags, $tags); 1366 } 1367 1368 public function test_export_question_with_tags_and_idnumber() { 1369 $this->resetAfterTest(); 1370 1371 // Create a question with tags. 1372 $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); 1373 $category = $generator->create_question_category(); 1374 $question = $generator->create_question('truefalse', null, 1375 ['category' => $category->id, 'idnumber' => 'myid']); 1376 core_tag_tag::set_item_tags('core_question', 'question', $question->id, 1377 context::instance_by_id($category->contextid), ['tag1', 'tag2'], 0); 1378 1379 // Export it. 1380 $questiondata = question_bank::load_question_data($question->id); 1381 $exporter = new qformat_gift(); 1382 $exporter->course = get_course(SITEID); 1383 $gift = $exporter->writequestion($questiondata); 1384 1385 // Verify. 1386 $expectedgift = "// question: {$question->id} name: True/false question 1387 // [id:myid] [tag:tag1] [tag:tag2] 1388 ::True/false question::[html]The answer is true.{TRUE#This is the wrong answer.#This is the right answer.####You should have selected true.} 1389 1390 "; 1391 1392 $this->assert_same_gift($expectedgift, $gift); 1393 } 1394 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body