<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
< /**
< * Unit tests for the Moodle GIFT format.
< *
< * @package qformat_gift
< * @copyright 2010 The Open University
< * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
< */
> namespace qformat_gift;
> use qformat_gift;
> use question_bank;
defined('MOODLE_INTERNAL') || die();
> use question_check_specified_fields_expectation;
global $CFG;
require_once($CFG->libdir . '/questionlib.php');
require_once($CFG->dirroot . '/question/format.php');
require_once($CFG->dirroot . '/question/format/gift/format.php');
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
<
/**
* Unit tests for the GIFT import/export format.
*
> * @package qformat_gift
* @copyright 2010 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
< class qformat_gift_test extends question_testcase {
> class giftformat_test extends \question_testcase {
public function assert_same_gift($expectedtext, $text) {
$this->assertEquals(str_replace("\r\n", "\n", $expectedtext),
str_replace("\r\n", "\n", $text));
}
public function test_import_essay() {
$gift = '
// essay
::Q8:: How are you? {}';
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Q8',
'questiontext' => 'How are you?',
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'essay',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array()),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_essay() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Q8',
'questiontext' => 'How are you?',
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'qtype' => 'essay',
'options' => (object) array(
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => '',
'graderinfoformat' => FORMAT_HTML,
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Q8
::Q8::How are you?{}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_import_match() {
$gift = '
// question: 2 name: Moodle activities
::Moodle activities::[html]Match the <b>activity</b> to the description.{
=[html]An activity supporting asynchronous discussions. -> Forum
=[moodle]A teacher asks a question and specifies a choice of multiple responses. -> Choice
=[plain]A bank of record entries which participants can add to. -> Database
=[markdown]A collection of web pages that anyone can add to or edit. -> Wiki
= -> Chat
}';
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Moodle activities',
'questiontext' => 'Match the <b>activity</b> to the description.',
'questiontextformat' => FORMAT_HTML,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_HTML,
'qtype' => 'match',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'shuffleanswers' => '1',
'correctfeedback' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
),
'partiallycorrectfeedback' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
),
'incorrectfeedback' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
),
'subquestions' => array(
0 => array(
'text' => 'An activity supporting asynchronous discussions.',
'format' => FORMAT_HTML,
'files' => array(),
),
1 => array(
'text' => 'A teacher asks a question and specifies a choice of multiple responses.',
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => 'A bank of record entries which participants can add to.',
'format' => FORMAT_PLAIN,
'files' => array(),
),
3 => array(
'text' => 'A collection of web pages that anyone can add to or edit.',
'format' => FORMAT_MARKDOWN,
'files' => array(),
),
4 => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array(),
),
),
'subanswers' => array(
0 => 'Forum',
1 => 'Choice',
2 => 'Database',
3 => 'Wiki',
4 => 'Chat',
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->subquestions, $q->subquestions);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_match() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Moodle activities',
'questiontext' => 'Match the <b>activity</b> to the description.',
'questiontextformat' => FORMAT_HTML,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_HTML,
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'qtype' => 'match',
'options' => (object) array(
'id' => 123,
'question' => 666,
'shuffleanswers' => 1,
'subquestions' => array(
42 => (object) array(
'id' => 1234,
'code' => 12341234,
'question' => 666,
'questiontext' => '<div class="frog">An activity supporting asynchronous discussions.</div>',
'questiontextformat' => FORMAT_HTML,
'answertext' => 'Forum',
),
43 => (object) array(
'id' => 1234,
'code' => 12341234,
'question' => 666,
'questiontext' => 'A teacher asks a question and specifies a choice of multiple responses.',
'questiontextformat' => FORMAT_MOODLE,
'answertext' => 'Choice',
),
44 => (object) array(
'id' => 1234,
'code' => 12341234,
'question' => 666,
'questiontext' => 'A bank of record entries which participants can add to.',
'questiontextformat' => FORMAT_PLAIN,
'answertext' => 'Database',
),
45 => (object) array(
'id' => 1234,
'code' => 12341234,
'question' => 666,
'questiontext' => 'A collection of web pages that anyone can add to or edit.',
'questiontextformat' => FORMAT_MARKDOWN,
'answertext' => 'Wiki',
),
46 => (object) array(
'id' => 1234,
'code' => 12341234,
'question' => 666,
'questiontext' => '',
'questiontextformat' => FORMAT_MARKDOWN,
'answertext' => 'Chat',
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Moodle activities
::Moodle activities::[html]Match the <b>activity</b> to the description.{
\t=<div class\\=\"frog\">An activity supporting asynchronous discussions.</div> -> Forum
\t=[moodle]A teacher asks a question and specifies a choice of multiple responses. -> Choice
\t=[plain]A bank of record entries which participants can add to. -> Database
\t=[markdown]A collection of web pages that anyone can add to or edit. -> Wiki
\t= -> Chat
}
";
$this->assert_same_gift($expectedgift, $gift);
}
/**
* Test import of multichoice question in GIFT format
*
* @dataProvider numberingstyle_provider
*
* @param string $numberingstyle multichoice numbering style to set for qtype_multichoice
*
*/
public function test_import_multichoice($numberingstyle) {
$this->resetAfterTest(true);
set_config('answernumbering', $numberingstyle, 'qtype_multichoice');
$gift = "
// multiple choice with specified feedback for right and wrong answers
::Q2:: What's between orange and green in the spectrum?
{
=yellow # right; good!
~red # [html]wrong, it's yellow
~[plain]blue # wrong, it's yellow
}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Q2',
'questiontext' => "What's between orange and green in the spectrum?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'multichoice',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'single' => 1,
'shuffleanswers' => '1',
'answernumbering' => $numberingstyle,
'correctfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'partiallycorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'incorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'answer' => array(
0 => array(
'text' => 'yellow',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => 'red',
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => 'blue',
'format' => FORMAT_PLAIN,
'files' => array(),
),
),
'fraction' => array(1, 0, 0),
'feedback' => array(
0 => array(
'text' => 'right; good!',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "wrong, it's yellow",
'format' => FORMAT_HTML,
'files' => array(),
),
2 => array(
'text' => "wrong, it's yellow",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
/**
* Return a list of numbering styles (see question/type/multichoice/questiontype.php
* for valid choices)
*
* @return array Array of 1-element arrays of qtype_multichoice numbering styles
*/
public function numberingstyle_provider() {
return [
['abc'],
['ABCD'],
['123'],
['iii'],
['IIII'],
['none']
];
}
public function test_import_multichoice_multi() {
$gift = "
// multiple choice, multiple response with specified feedback for right and wrong answers
::colours:: What's between orange and green in the spectrum?
{
~%50%yellow # right; good!
~%-100%red # [html]wrong
~%50%off-beige # right; good!
~%-100%[plain]blue # wrong
}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'colours',
'questiontext' => "What's between orange and green in the spectrum?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'multichoice',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'single' => 0,
'shuffleanswers' => '1',
'answernumbering' => 'abc',
'correctfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'partiallycorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'incorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'answer' => array(
0 => array(
'text' => 'yellow',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => 'red',
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => 'off-beige',
'format' => FORMAT_MOODLE,
'files' => array(),
),
3 => array(
'text' => 'blue',
'format' => FORMAT_PLAIN,
'files' => array(),
),
),
'fraction' => array(0.5, -1, 0.5, -1),
'feedback' => array(
0 => array(
'text' => 'right; good!',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "wrong",
'format' => FORMAT_HTML,
'files' => array(),
),
2 => array(
'text' => "right; good!",
'format' => FORMAT_MOODLE,
'files' => array(),
),
3 => array(
'text' => "wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_multichoice_multi_tricky() {
$gift = "
// multiple choice, multiple response with specified feedback for right and wrong answers
::colours:: What's between orange and green in the spectrum?
{
~%100%yellow # right; good!
~%-50%red # wrong
~%-50%blue # wrong
}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'colours',
'questiontext' => "What's between orange and green in the spectrum?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'multichoice',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'single' => 0,
'shuffleanswers' => '1',
'answernumbering' => 'abc',
'correctfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'partiallycorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'incorrectfeedback' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'answer' => array(
0 => array(
'text' => 'yellow',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => 'red',
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => 'blue',
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
'fraction' => array(1, -0.5, -0.5),
'feedback' => array(
0 => array(
'text' => 'right; good!',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => "wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_multichoice() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Q8',
'questiontext' => "What's between orange and green in the spectrum?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'qtype' => 'multichoice',
'options' => (object) array(
'single' => 1,
'shuffleanswers' => '1',
'answernumbering' => 'abc',
'correctfeedback' => '',
'correctfeedbackformat' => FORMAT_MOODLE,
'partiallycorrectfeedback' => '',
'partiallycorrectfeedbackformat' => FORMAT_MOODLE,
'incorrectfeedback' => '',
'incorrectfeedbackformat' => FORMAT_MOODLE,
'answers' => array(
123 => (object) array(
'id' => 123,
'answer' => 'yellow',
'answerformat' => FORMAT_MOODLE,
'fraction' => 1,
'feedback' => 'right; good!',
'feedbackformat' => FORMAT_MOODLE,
),
124 => (object) array(
'id' => 124,
'answer' => 'red',
'answerformat' => FORMAT_MOODLE,
'fraction' => 0,
'feedback' => "wrong, it's yellow",
'feedbackformat' => FORMAT_HTML,
),
125 => (object) array(
'id' => 125,
'answer' => 'blue',
'answerformat' => FORMAT_PLAIN,
'fraction' => 0,
'feedback' => "wrong, it's yellow",
'feedbackformat' => FORMAT_MOODLE,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Q8
::Q8::What's between orange and green in the spectrum?{
\t=yellow#right; good!
\t~red#[html]wrong, it's yellow
\t~[plain]blue#wrong, it's yellow
}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_export_multichoice_multi_tricky() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Q8',
'questiontext' => "What's between orange and green in the spectrum?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'qtype' => 'multichoice',
'options' => (object) array(
'single' => 0,
'shuffleanswers' => '1',
'answernumbering' => 'abc',
'correctfeedback' => '',
'correctfeedbackformat' => FORMAT_MOODLE,
'partiallycorrectfeedback' => '',
'partiallycorrectfeedbackformat' => FORMAT_MOODLE,
'incorrectfeedback' => '',
'incorrectfeedbackformat' => FORMAT_MOODLE,
'answers' => array(
123 => (object) array(
'id' => 123,
'answer' => 'yellow',
'answerformat' => FORMAT_MOODLE,
'fraction' => 1,
'feedback' => 'right; good!',
'feedbackformat' => FORMAT_MOODLE,
),
124 => (object) array(
'id' => 124,
'answer' => 'red',
'answerformat' => FORMAT_MOODLE,
'fraction' => -0.5,
'feedback' => "wrong, it's yellow",
'feedbackformat' => FORMAT_MOODLE,
),
125 => (object) array(
'id' => 125,
'answer' => 'blue',
'answerformat' => FORMAT_MOODLE,
'fraction' => -0.5,
'feedback' => "wrong, it's yellow",
'feedbackformat' => FORMAT_MOODLE,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Q8
::Q8::What's between orange and green in the spectrum?{
\t~%100%yellow#right; good!
\t~%-50%red#wrong, it's yellow
\t~%-50%blue#wrong, it's yellow
}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_import_numerical() {
$gift = "
// math range question
::Q5:: What is a number from 1 to 5? {#3:2~#Completely wrong}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Q5',
'questiontext' => "What is a number from 1 to 5?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'numerical',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'answer' => array(
'3',
'*',
),
'fraction' => array(1, 0),
'feedback' => array(
0 => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "Completely wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
< 'tolerance' => array(2, 0),
> 'tolerance' => array(2, ''),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->fraction, $q->fraction);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_numerical() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Q5',
'questiontext' => "What is a number from 1 to 5?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'qtype' => 'numerical',
'options' => (object) array(
'id' => 123,
'question' => 666,
'unitsleft' => 0,
'showunits' => 2,
'unitgradingtype' => 0,
'unitpenalty' => 0,
'answers' => array(
1 => (object) array(
'id' => 123,
'answer' => '3',
'answerformat' => 0,
'fraction' => 1,
'tolerance' => 2,
'feedback' => '',
'feedbackformat' => FORMAT_MOODLE,
),
2 => (object) array(
'id' => 124,
'answer' => '*',
'answerformat' => 0,
'fraction' => 0,
'tolerance' => 0,
'feedback' => "Completely wrong",
'feedbackformat' => FORMAT_MOODLE,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Q5
::Q5::What is a number from 1 to 5?{#
\t=%100%3:2#
\t~#Completely wrong
}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_import_shortanswer() {
$gift = "
// question: 666 name: Shortanswer
::Shortanswer::Which is the best animal?{
=Frog#Good!
=%50%Cat#What is it with Moodlers and cats?
=%0%*#Completely wrong
}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Shortanswer',
'questiontext' => "Which is the best animal?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'shortanswer',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'answer' => array(
'Frog',
'Cat',
'*',
),
'fraction' => array(1, 0.5, 0),
'feedback' => array(
0 => array(
'text' => 'Good!',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "What is it with Moodlers and cats?",
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => "Completely wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->fraction, $q->fraction);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_shortanswer_with_general_feedback() {
$gift = "
// question: 666 name: Shortanswer
::Shortanswer::Which is the best animal?{
=Frog#Good!
=%50%Cat#What is it with Moodlers and cats?
=%0%*#Completely wrong
####[html]Here is some general feedback!
}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Shortanswer',
'questiontext' => "Which is the best animal?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => 'Here is some general feedback!',
'generalfeedbackformat' => FORMAT_HTML,
'qtype' => 'shortanswer',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'answer' => array(
'Frog',
'Cat',
'*',
),
'fraction' => array(1, 0.5, 0),
'feedback' => array(
0 => array(
'text' => 'Good!',
'format' => FORMAT_MOODLE,
'files' => array(),
),
1 => array(
'text' => "What is it with Moodlers and cats?",
'format' => FORMAT_MOODLE,
'files' => array(),
),
2 => array(
'text' => "Completely wrong",
'format' => FORMAT_MOODLE,
'files' => array(),
),
),
);
// Repeated test for better failure messages.
$this->assertEquals($expectedq->answer, $q->answer);
$this->assertEquals($expectedq->fraction, $q->fraction);
$this->assertEquals($expectedq->feedback, $q->feedback);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_shortanswer() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Shortanswer',
'questiontext' => "Which is the best animal?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'qtype' => 'shortanswer',
'options' => (object) array(
'id' => 123,
'questionid' => 666,
'usecase' => 1,
'answers' => array(
1 => (object) array(
'id' => 1,
'answer' => 'Frog',
'answerformat' => 0,
'fraction' => 1,
'feedback' => 'Good!',
'feedbackformat' => FORMAT_MOODLE,
),
2 => (object) array(
'id' => 2,
'answer' => 'Cat',
'answerformat' => 0,
'fraction' => 0.5,
'feedback' => "What is it with Moodlers and cats?",
'feedbackformat' => FORMAT_MOODLE,
),
3 => (object) array(
'id' => 3,
'answer' => '*',
'answerformat' => 0,
'fraction' => 0,
'feedback' => "Completely wrong",
'feedbackformat' => FORMAT_MOODLE,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Shortanswer
::Shortanswer::Which is the best animal?{
\t=%100%Frog#Good!
\t=%50%Cat#What is it with Moodlers and cats?
\t=%0%*#Completely wrong
}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_export_shortanswer_with_general_feedback() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Shortanswer',
'questiontext' => "Which is the best animal?",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => 'Here is some general feedback!',
'generalfeedbackformat' => FORMAT_HTML,
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'qtype' => 'shortanswer',
'options' => (object) array(
'id' => 123,
'questionid' => 666,
'usecase' => 1,
'answers' => array(
1 => (object) array(
'id' => 1,
'answer' => 'Frog',
'answerformat' => 0,
'fraction' => 1,
'feedback' => 'Good!',
'feedbackformat' => FORMAT_MOODLE,
),
2 => (object) array(
'id' => 2,
'answer' => 'Cat',
'answerformat' => 0,
'fraction' => 0.5,
'feedback' => "What is it with Moodlers and cats?",
'feedbackformat' => FORMAT_MOODLE,
),
3 => (object) array(
'id' => 3,
'answer' => '*',
'answerformat' => 0,
'fraction' => 0,
'feedback' => "Completely wrong",
'feedbackformat' => FORMAT_MOODLE,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Shortanswer
::Shortanswer::Which is the best animal?{
\t=%100%Frog#Good!
\t=%50%Cat#What is it with Moodlers and cats?
\t=%0%*#Completely wrong
\t####[html]Here is some general feedback!
}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_import_truefalse() {
$gift = "
// true/false
::Q1:: 42 is the Absolute Answer to everything.{
FALSE#42 is the Ultimate Answer.#You gave the right answer.}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Q1',
'questiontext' => "42 is the Absolute Answer to everything.",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'truefalse',
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'correctanswer' => 0,
'feedbacktrue' => array(
'text' => '42 is the Ultimate Answer.',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'feedbackfalse' => array(
'text' => 'You gave the right answer.',
'format' => FORMAT_MOODLE,
'files' => array(),
),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_truefalse_true_answer1() {
$gift = "// name 0-11
::2-08 TSL::TSL is blablabla.{T}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => '2-08 TSL',
'questiontext' => "TSL is blablabla.",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'truefalse',
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'correctanswer' => 1,
'feedbacktrue' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'feedbackfalse' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_truefalse_true_answer2() {
$gift = "// name 0-11
::2-08 TSL::TSL is blablabla.{TRUE}";
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => '2-08 TSL',
'questiontext' => "TSL is blablabla.",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'truefalse',
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'correctanswer' => 1,
'feedbacktrue' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
'feedbackfalse' => array(
'text' => '',
'format' => FORMAT_MOODLE,
'files' => array(),
),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_export_truefalse() {
$qdata = (object) array(
'id' => 666 ,
'name' => 'Q1',
'questiontext' => "42 is the Absolute Answer to everything.",
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 1,
'length' => 1,
'qtype' => 'truefalse',
'options' => (object) array(
'id' => 123,
'question' => 666,
'trueanswer' => 1,
'falseanswer' => 2,
'answers' => array(
1 => (object) array(
'id' => 123,
'answer' => 'True',
'answerformat' => 0,
'fraction' => 1,
'feedback' => 'You gave the right answer.',
'feedbackformat' => FORMAT_MOODLE,
),
2 => (object) array(
'id' => 124,
'answer' => 'False',
'answerformat' => 0,
'fraction' => 0,
'feedback' => "42 is the Ultimate Answer.",
'feedbackformat' => FORMAT_HTML,
),
),
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: Q1
::Q1::42 is the Absolute Answer to everything.{TRUE#[html]42 is the Ultimate Answer.#You gave the right answer.}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_export_backslash() {
// There was a bug (MDL-34171) where \\ was getting exported as \\, not
// \\\\, and on import, \\ in converted to \.
// We need \\\\ in the test code, because of PHPs string escaping rules.
$qdata = (object) array(
'id' => 666 ,
'name' => 'backslash',
'questiontext' => 'A \\ B \\\\ C',
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'qtype' => 'essay',
'options' => (object) array(
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => '',
'graderinfoformat' => FORMAT_HTML,
),
);
$exporter = new qformat_gift();
$gift = $exporter->writequestion($qdata);
$expectedgift = "// question: 666 name: backslash
::backslash::A \\\\ B \\\\\\\\ C{}
";
$this->assert_same_gift($expectedgift, $gift);
}
public function test_import_backslash() {
// There was a bug (MDL-34171) where \\ in the import was getting changed
// to \. This test checks for that.
// We need \\\\ in the test code, because of PHPs string escaping rules.
$gift = '
// essay
::double backslash:: A \\\\ B \\\\\\\\ C{}';
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'double backslash',
'questiontext' => 'A \\ B \\\\ C',
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'essay',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array()),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_pre_content() {
$gift = '
::Q001::[html]<p>What would running the test method print?</p>
<pre>
public void test() \{
method1();
method2();
method3();
\}
</pre>
{}';
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Q001',
'questiontext' => '<p>What would running the test method print?</p>
<pre>
public void test() {
method1();
method2();
method3();
}
</pre>',
'questiontextformat' => FORMAT_HTML,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_HTML,
'qtype' => 'essay',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array()),
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
public function test_import_question_with_tags() {
$gift = '
// This question is to test importing tags: [tag:tag] [tag:other-tag].
// And an idnumber: [id:myid].
::Question name:: How are you? {}';
$lines = preg_split('/[\\n\\r]/', str_replace("\r\n", "\n", $gift));
$importer = new qformat_gift();
$q = $importer->readquestion($lines);
$expectedq = (object) array(
'name' => 'Question name',
'questiontext' => 'How are you?',
'questiontextformat' => FORMAT_MOODLE,
'generalfeedback' => '',
'generalfeedbackformat' => FORMAT_MOODLE,
'qtype' => 'essay',
'defaultmark' => 1,
'penalty' => 0.3333333,
'length' => 1,
'responseformat' => 'editor',
'responsefieldlines' => 15,
'attachments' => 0,
'graderinfo' => array(
'text' => '',
'format' => FORMAT_HTML,
'files' => array()),
'tags' => ['tag', 'other-tag'],
'idnumber' => 'myid',
);
$this->assert(new question_check_specified_fields_expectation($expectedq), $q);
}
/**
* Data provider for test_extract_idnumber_and_tags_from_comment.
*
* @return array the test cases.
*/
public function extract_idnumber_and_tags_from_comment_testcases() {
return [
'blank comment' => ['', [], ''],
'nothing in comment' => ['', [], '// A basic comment.'],
'idnumber only' => ['frog', [], '// A comment with [id:frog] <-- an idnumber.'],
'tags only' => ['', ['frog', 'toad'], '// Look tags: [tag:frog] [tag:toad].'],
'everything' => ['four', ['add', 'basic'], '// [tag:add] [tag:basic] [id:four]'],
'everything mixed up' => ['four', ['basic', 'add'],
"// [tag: basic] Here is \n// a [id: four ] que[tag:add ]stion."],
'split over line' => ['', [], "// Ceci n\'est pas une [tag:\n\\ frog]."],
'escape ] idnumber' => ['i]d', [], '// [id:i\]d].'],
'escape ] tag' => ['', ['t]ag'], '// [tag:t\]ag].'],
];
}
/**
* Test extract_idnumber_and_tags_from_comment.
*
* @dataProvider extract_idnumber_and_tags_from_comment_testcases
* @param string $expectedidnumber the expected idnumber.
* @param array $expectedtags the expected tags.
* @param string $comment the comment to parse.
*/
public function test_extract_idnumber_and_tags_from_comment(
string $expectedidnumber, array $expectedtags, string $comment) {
$importer = new qformat_gift();
list($idnumber, $tags) = $importer->extract_idnumber_and_tags_from_comment($comment);
$this->assertSame($expectedidnumber, $idnumber);
$this->assertSame($expectedtags, $tags);
}
public function test_export_question_with_tags_and_idnumber() {
$this->resetAfterTest();
// Create a question with tags.
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $generator->create_question_category();
$question = $generator->create_question('truefalse', null,
['category' => $category->id, 'idnumber' => 'myid']);
< core_tag_tag::set_item_tags('core_question', 'question', $question->id,
< context::instance_by_id($category->contextid), ['tag1', 'tag2'], 0);
> \core_tag_tag::set_item_tags('core_question', 'question', $question->id,
> \context::instance_by_id($category->contextid), ['tag1', 'tag2'], 0);
// Export it.
$questiondata = question_bank::load_question_data($question->id);
$exporter = new qformat_gift();
$exporter->course = get_course(SITEID);
$gift = $exporter->writequestion($questiondata);
// Verify.
$expectedgift = "// question: {$question->id} name: True/false question
// [id:myid] [tag:tag1] [tag:tag2]
::True/false question::[html]The answer is true.{TRUE#This is the wrong answer.#This is the right answer.####You should have selected true.}
";
$this->assert_same_gift($expectedgift, $gift);
}
}