diff --git a/question/format/gift/format.php b/question/format/gift/format.php
index d8d037ddcd9..1949d84b5fc 100755
--- a/question/format/gift/format.php
+++ b/question/format/gift/format.php
@@ -54,29 +54,31 @@ class qformat_gift extends qformat_default {
return $answer_weight;
}
- function commentparser(&$answer) {
- if (strpos($answer,"#") > 0) {
- $hashpos = strpos($answer,"#");
- $comment = substr($answer, $hashpos+1);
- $comment = trim($this->escapedchar_post($comment));
- $answer = substr($answer, 0, $hashpos);
+ function commentparser($answer, $defaultformat) {
+ $bits = explode('#', $answer, 2);
+ $ans = $this->parse_text_with_format(trim($bits[0]), $defaultformat);
+ if (count($bits) > 1) {
+ $feedback = $this->parse_text_with_format(trim($bits[1]), $defaultformat);
} else {
- $comment = " ";
+ $feedback = array('text' => '', 'format' => $defaultformat, 'files' => array());
}
- return $comment;
+ return array($ans, $feedback);
}
- function split_truefalse_comment($comment) {
- // splits up comment around # marks
- // returns an array of true/false feedback
- $bits = explode('#',$comment);
- $feedback = array('wrong' => $bits[0]);
- if (count($bits) >= 2) {
- $feedback['right'] = $bits[1];
+ function split_truefalse_comment($answer, $defaultformat) {
+ $bits = explode('#', $answer, 3);
+ $ans = $this->parse_text_with_format(trim($bits[0]), $defaultformat);
+ if (count($bits) > 1) {
+ $wrongfeedback = $this->parse_text_with_format(trim($bits[1]), $defaultformat);
} else {
- $feedback['right'] = '';
+ $wrongfeedback = array('text' => '', 'format' => $defaultformat, 'files' => array());
}
- return $feedback;
+ if (count($bits) > 2) {
+ $rightfeedback = $this->parse_text_with_format(trim($bits[2]), $defaultformat);
+ } else {
+ $rightfeedback = array('text' => '', 'format' => $defaultformat, 'files' => array());
+ }
+ return array($ans, $wrongfeedback, $rightfeedback);
}
function escapedchar_pre($string) {
@@ -110,6 +112,24 @@ class qformat_gift extends qformat_default {
return true;
}
+ protected function parse_text_with_format($text, $defaultformat = FORMAT_MOODLE) {
+ $result = array(
+ 'text' => $text,
+ 'format' => $defaultformat,
+ 'files' => array(),
+ );
+ if (strpos($text, '[') === 0) {
+ $formatend = strpos($text, ']');
+ $result['format'] = $this->format_name_to_const(substr($text, 1, $formatend - 1));
+ if ($result['format'] == -1) {
+ $result['format'] = $defaultformat;
+ } else {
+ $result['text'] = substr($text, $formatend + 1);
+ }
+ }
+ $result['text'] = trim($this->escapedchar_post($result['text']));
+ return $result;
+ }
function readquestion($lines) {
// Given an array of lines known to define a question in this format, this function
@@ -196,18 +216,10 @@ class qformat_gift extends qformat_default {
}
// Get questiontext format from questiontext
- $questiontextformat = FORMAT_MOODLE;
- if (strpos($questiontext, '[') === 0) {
- $formatend = strpos($questiontext, ']');
- $questiontextformat = $this->format_name_to_const(substr($questiontext, 1, $formatend));
- if ($questiontextformat == -1) {
- $questiontextformat = FORMAT_MOODLE;
- } else {
- $questiontext = substr($questiontext, $formatend + 1);
- }
- }
- $question->questiontextformat = $questiontextformat;
- $question->questiontext = trim($this->escapedchar_post($questiontext));
+ $text = $this->parse_text_with_format($questiontext);
+ $question->questiontextformat = $text['format'];
+ $question->generalfeedbackformat = $text['format'];
+ $question->questiontext = $text['text'];
// set question name if not already set
if ($question->name === false) {
@@ -279,7 +291,7 @@ class qformat_gift extends qformat_default {
case ESSAY:
$question->fraction = 0;
$question->feedback['text'] = '';
- $question->feedback['format'] = $questiontextformat;
+ $question->feedback['format'] = $question->questiontextformat;
$question->feedback['files'] = array();
return $question;
break;
@@ -290,13 +302,13 @@ class qformat_gift extends qformat_default {
$question->single = 1; // only one answer allowed (the default)
}
$question->correctfeedback['text'] = '';
- $question->correctfeedback['format'] = $questiontextformat;
+ $question->correctfeedback['format'] = $question->questiontextformat;
$question->correctfeedback['files'] = array();
$question->partiallycorrectfeedback['text'] = '';
- $question->partiallycorrectfeedback['format'] = $questiontextformat;
+ $question->partiallycorrectfeedback['format'] = $question->questiontextformat;
$question->partiallycorrectfeedback['files'] = array();
$question->incorrectfeedback['text'] = '';
- $question->incorrectfeedback['format'] = $questiontextformat;
+ $question->incorrectfeedback['format'] = $question->questiontextformat;
$question->incorrectfeedback['files'] = array();
$answertext = str_replace("=", "~=", $answertext);
@@ -329,14 +341,9 @@ class qformat_gift extends qformat_default {
} else { //default, i.e., wrong anwer
$answer_weight = 0;
}
- $question->answer[$key]['text'] =
- $this->escapedchar_post($answer);
- $question->answer[$key]['format'] = $questiontextformat;
- $question->answer[$key]['files'] = array();
+ list($question->answer[$key], $question->feedback[$key]) =
+ $this->commentparser($answer, $question->questiontextformat);
$question->fraction[$key] = $answer_weight;
- $question->feedback[$key]['text'] = $this->commentparser($answer); // commentparser also removes comment from $answer
- $question->feedback[$key]['format'] = $questiontextformat;
- $question->feedback[$key]['files'] = array();
} // end foreach answer
//$question->defaultgrade = 1;
@@ -368,38 +375,30 @@ class qformat_gift extends qformat_default {
}
$marker = strpos($answer, '->');
- $question->subquestions[$key]['text'] =
- trim($this->escapedchar_post(substr($answer, 0, $marker)));
- $question->subquestions[$key]['format'] = $questiontextformat;
- $question->subquestions[$key]['files'] = array();
- $question->subanswers[$key] =
- trim($this->escapedchar_post(substr($answer, $marker + 2)));
- } // end foreach answer
+ $question->subquestions[$key] = $this->parse_text_with_format(
+ substr($answer, 0, $marker), $question->questiontextformat);
+ $question->subanswers[$key] = trim($this->escapedchar_post(
+ substr($answer, $marker + 2)));
+ }
return $question;
break;
case TRUEFALSE:
- $answer = $answertext;
- $comment = $this->commentparser($answer); // commentparser also removes comment from $answer
- $feedback = $this->split_truefalse_comment($comment);
+ list($answer, $wrongfeedback, $rightfeedback) =
+ $this->split_truefalse_comment($answertext, $question->questiontextformat);
if ($answer == "T" OR $answer == "TRUE") {
- $question->answer = 1;
- $question->feedbacktrue['text'] = $feedback['right'];
- $question->feedbackfalse['text'] = $feedback['wrong'];
+ $question->correctanswer = 1;
+ $question->feedbacktrue = $rightfeedback;
+ $question->feedbackfalse = $wrongfeedback;
} else {
- $question->answer = 0;
- $question->feedbackfalse['text'] = $feedback['right'];
- $question->feedbacktrue['text'] = $feedback['wrong'];
+ $question->correctanswer = 0;
+ $question->feedbacktrue = $wrongfeedback;
+ $question->feedbackfalse = $rightfeedback;
}
- $question->feedbackfalse['format'] = $questiontextformat;
- $question->feedbacktrue['format'] = $questiontextformat;
- $question->feedbackfalse['files'] = array();
- $question->feedbacktrue['files'] = array();
$question->penalty = 1;
- $question->correctanswer = $question->answer;
return $question;
break;
@@ -414,7 +413,7 @@ class qformat_gift extends qformat_default {
array_shift($answers);
}
- if (!$this->check_answer_count(1,$answers,$text)) {
+ if (!$this->check_answer_count(1, $answers, $text)) {
return false;
break;
}
@@ -422,22 +421,20 @@ class qformat_gift extends qformat_default {
foreach ($answers as $key => $answer) {
$answer = trim($answer);
- // Answer Weight
+ // Answer weight
if (preg_match($gift_answerweight_regex, $answer)) { // check for properly formatted answer weight
$answer_weight = $this->answerweightparser($answer);
} else { //default, i.e., full-credit anwer
$answer_weight = 1;
}
- $question->answer[$key] = $this->escapedchar_post($answer);
- $question->fraction[$key] = $answer_weight;
- $question->feedback[$key]['text'] = $this->commentparser($answer); //commentparser also removes comment from $answer
- $question->feedback[$key]['format'] = $questiontextformat;
- $question->feedback[$key]['files'] = array();
- } // end foreach
- //$question->usecase = 0; // Ignore case
- //$question->defaultgrade = 1;
- //$question->image = ""; // No images with this format
+ list($answer, $question->feedback[$key]) = $this->commentparser(
+ $answer, $question->questiontextformat);
+
+ $question->answer[$key] = $answer['text'];
+ $question->fraction[$key] = $answer_weight;
+ }
+
return $question;
break;
@@ -478,10 +475,11 @@ class qformat_gift extends qformat_default {
} else { //default, i.e., full-credit anwer
$answer_weight = 1;
}
+
+ list($answer, $question->feedback[$key]) = $this->commentparser(
+ $answer, $question->questiontextformat);
$question->fraction[$key] = $answer_weight;
- $question->feedback[$key]['text'] = $this->commentparser($answer); //commentparser also removes comment from $answer
- $question->feedback[$key]['format'] = $questiontextformat;
- $question->feedback[$key]['files'] = array();
+ $answer = $answer['text'];
//Calculate Answer and Min/Max values
if (strpos($answer,"..") > 0) { // optional [min]..[max] format
@@ -509,14 +507,13 @@ class qformat_gift extends qformat_default {
// store results
$question->answer[$key] = $ans;
$question->tolerance[$key] = $tol;
- } // end foreach
+ }
if ($wrongfeedback) {
$key += 1;
$question->fraction[$key] = 0;
- $question->feedback[$key]['text'] = $this->commentparser($wrongfeedback);
- $question->feedback[$key]['format'] = $questiontextformat;
- $question->feedback[$key]['files'] = array();
+ list($notused, $question->feedback[$key]) = $this->commentparser(
+ $wrongfeedback, $question->questiontextformat);
$question->answer[$key] = '*';
$question->tolerance[$key] = '';
}
@@ -526,7 +523,7 @@ class qformat_gift extends qformat_default {
default:
$this->error(get_string('giftnovalidquestion', 'quiz'), $text);
- return false;
+ return fale;
break;
}
@@ -569,7 +566,7 @@ class qformat_gift extends qformat_default {
if ($format == 'moodle') {
return FORMAT_MOODLE;
} else if ($format == 'html') {
- return FORMAT_PLAIN;
+ return FORMAT_HTML;
} else if ($format == 'plain') {
return FORMAT_PLAIN;
} else if ($format == 'markdown') {
@@ -583,9 +580,9 @@ class qformat_gift extends qformat_default {
return '::' . $this->repchar($name) . '::';
}
- public function write_questiontext($text, $format) {
+ public function write_questiontext($text, $format, $defaultformat = FORMAT_MOODLE) {
$output = '';
- if ($format != FORMAT_MOODLE) {
+ if ($text != '' && $format != $defaultformat) {
$output .= '[' . $this->format_const_to_name($format) . ']';
}
$output .= $this->repchar($text, $format);
@@ -596,7 +593,7 @@ class qformat_gift extends qformat_default {
global $QTYPES, $OUTPUT;
// Start with a comment
- $expout = "// question: $question->id name: $question->name \n";
+ $expout = "// question: $question->id name: $question->name\n";
// output depends on question type
switch($question->qtype) {
@@ -622,27 +619,28 @@ class qformat_gift extends qformat_default {
$falseanswer = $question->options->answers[$question->options->falseanswer];
if ($trueanswer->fraction == 1) {
$answertext = 'TRUE';
- $right_feedback = $trueanswer->feedback;
- $wrong_feedback = $falseanswer->feedback;
+ $rightfeedback = $this->write_questiontext($trueanswer->feedback,
+ $trueanswer->feedbackformat, $question->questiontextformat);
+ $wrongfeedback = $this->write_questiontext($falseanswer->feedback,
+ $falseanswer->feedbackformat, $question->questiontextformat);
} else {
$answertext = 'FALSE';
- $right_feedback = $falseanswer->feedback;
- $wrong_feedback = $trueanswer->feedback;
+ $rightfeedback = $this->write_questiontext($falseanswer->feedback,
+ $falseanswer->feedbackformat, $question->questiontextformat);
+ $wrongfeedback = $this->write_questiontext($trueanswer->feedback,
+ $trueanswer->feedbackformat, $question->questiontextformat);
}
- $wrong_feedback = $this->repchar($wrong_feedback);
- $right_feedback = $this->repchar($right_feedback);
-
$expout .= $this->write_name($question->name);
$expout .= $this->write_questiontext($question->questiontext, $question->questiontextformat);
$expout .= '{' . $this->repchar($answertext);
- if ($wrong_feedback) {
- $expout .= '#' . $wrong_feedback;
- } else if ($right_feedback) {
+ if ($wrongfeedback) {
+ $expout .= '#' . $wrongfeedback;
+ } else if ($rightfeedback) {
$expout .= '#';
}
- if ($right_feedback) {
- $expout .= '#' . $right_feedback;
+ if ($rightfeedback) {
+ $expout .= '#' . $rightfeedback;
}
$expout .= "}\n";
break;
@@ -660,9 +658,11 @@ class qformat_gift extends qformat_default {
$weight = $answer->fraction * 100;
$answertext = '~%' . $weight . '%';
}
- $expout .= "\t" . $answertext . $this->repchar($answer->answer);
+ $expout .= "\t" . $answertext . $this->write_questiontext($answer->answer,
+ $answer->answerformat, $question->questiontextformat);
if ($answer->feedback != '') {
- $expout .= '#' . $this->repchar($answer->feedback);
+ $expout .= '#' . $this->write_questiontext($answer->feedback,
+ $answer->feedbackformat, $question->questiontextformat);
}
$expout .= "\n";
}
@@ -676,7 +676,8 @@ class qformat_gift extends qformat_default {
foreach($question->options->answers as $answer) {
$weight = 100 * $answer->fraction;
$expout .= "\t=%" . $weight . '%' . $this->repchar($answer->answer) .
- '#' . $this->repchar($answer->feedback) . "\n";
+ '#' . $this->write_questiontext($answer->feedback,
+ $answer->feedbackformat, $question->questiontextformat) . "\n";
}
$expout .= "}\n";
break;
@@ -689,9 +690,11 @@ class qformat_gift extends qformat_default {
if ($answer->answer != '' && $answer->answer != '*') {
$weight = 100 * $answer->fraction;
$expout .= "\t=%" . $weight . '%' . $answer->answer . ':' .
- (float)$answer->tolerance . '#' . $this->repchar($answer->feedback) . "\n";
+ (float)$answer->tolerance . '#' . $this->write_questiontext($answer->feedback,
+ $answer->feedbackformat, $question->questiontextformat) . "\n";
} else {
- $expout .= "\t~#" . $this->repchar($answer->feedback) . "\n";
+ $expout .= "\t~#" . $this->write_questiontext($answer->feedback,
+ $answer->feedbackformat, $question->questiontextformat) . "\n";
}
}
$expout .= "}\n";
@@ -702,7 +705,7 @@ class qformat_gift extends qformat_default {
$expout .= $this->write_questiontext($question->questiontext, $question->questiontextformat);
$expout .= "{\n";
foreach($question->options->subquestions as $subquestion) {
- $expout .= "\t=" . $this->repchar($subquestion->questiontext) .
+ $expout .= "\t=" . $this->repchar($this->write_questiontext($subquestion->questiontext, $subquestion->questiontextformat, $question->questiontextformat)) .
' -> ' . $this->repchar($subquestion->answertext) . "\n";
}
$expout .= "}\n";
diff --git a/question/format/gift/simpletest/testgiftformat.php b/question/format/gift/simpletest/testgiftformat.php
new file mode 100644
index 00000000000..da66ac7e4b0
--- /dev/null
+++ b/question/format/gift/simpletest/testgiftformat.php
@@ -0,0 +1,710 @@
+.
+
+
+/**
+ * Unit tests for the Moodle GIFT format.
+ *
+ * @package qformat_xml
+ * @copyright 2010 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once($CFG->libdir . '/questionlib.php');
+require_once($CFG->dirroot . '/question/format.php');
+require_once($CFG->dirroot . '/question/format/gift/format.php');
+
+
+/**
+ * Unit tests for the GIFT import/export format.
+ *
+ * @copyright 2010 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qformat_gift_test extends UnitTestCase {
+ public function assert_same_gift($expectedtext, $text) {
+ $this->assertEqual(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',
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ 'length' => 1,
+ 'feedback' => array(
+ 'text' => '',
+ 'format' => FORMAT_MOODLE,
+ 'files' => array(),
+ ),
+ );
+
+ $this->assert(new CheckSpecifiedFieldsExpectation($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,
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ 'length' => 1,
+ 'qtype' => 'essay',
+ 'options' => (object) array(
+ 'answers' => array(
+ 123 => (object) array(
+ 'id' => 123,
+ 'answer' => 666,
+ 'answerformat' => FORMAT_MOODLE,
+ 'fraction' => 0,
+ 'feedback' => '',
+ 'feedbackformat' => FORMAT_MOODLE,
+ ),
+ ),
+ ),
+ );
+
+ $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 activity 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 activity to the description.',
+ 'questiontextformat' => FORMAT_HTML,
+ 'generalfeedback' => '',
+ 'generalfeedbackformat' => FORMAT_HTML,
+ 'qtype' => 'match',
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ 'length' => 1,
+ 'shuffleanswers' => '1',
+ '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->assertEqual($expectedq->subquestions, $q->subquestions);
+ $this->assert(new CheckSpecifiedFieldsExpectation($expectedq), $q);
+ }
+
+ public function test_export_match() {
+ $qdata = (object) array(
+ 'id' => 666 ,
+ 'name' => 'Moodle activities',
+ 'questiontext' => 'Match the activity to the description.',
+ 'questiontextformat' => FORMAT_HTML,
+ 'generalfeedback' => '',
+ 'generalfeedbackformat' => FORMAT_HTML,
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ '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' => 'An activity supporting asynchronous discussions.',
+ '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 activity to the description.{
+\t=An activity supporting asynchronous discussions. -> 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);
+ }
+
+ public function test_import_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',
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ 'length' => 1,
+ 'single' => 1,
+ '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_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->assertEqual($expectedq->answer, $q->answer);
+ $this->assertEqual($expectedq->feedback, $q->feedback);
+ $this->assert(new CheckSpecifiedFieldsExpectation($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,
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ '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_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',
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ '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),
+ );
+
+ // Repeated test for better failure messages.
+ $this->assertEqual($expectedq->answer, $q->answer);
+ $this->assertEqual($expectedq->fraction, $q->fraction);
+ $this->assertEqual($expectedq->feedback, $q->feedback);
+ $this->assert(new CheckSpecifiedFieldsExpectation($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,
+ 'defaultgrade' => 1,
+ 'penalty' => 1,
+ 'length' => 1,
+ 'qtype' => 'numerical',
+ 'options' => (object) array(
+ 'id' => 123,
+ 'question' => 666,
+ 'instructions' => '',
+ 'instructionsformat' => FORMAT_MOODLE,
+ 'showunits' => 0,
+ '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',
+ 'defaultgrade' => 1,
+ 'penalty' => 0.1,
+ '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->assertEqual($expectedq->answer, $q->answer);
+ $this->assertEqual($expectedq->fraction, $q->fraction);
+ $this->assertEqual($expectedq->feedback, $q->feedback);
+ $this->assert(new CheckSpecifiedFieldsExpectation($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,
+ 'defaultgrade' => 1,
+ 'penalty' => 1,
+ 'length' => 1,
+ 'qtype' => 'shortanswer',
+ 'options' => (object) array(
+ 'id' => 123,
+ 'question' => 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_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',
+ 'defaultgrade' => 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 CheckSpecifiedFieldsExpectation($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,
+ 'defaultgrade' => 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);
+ }
+}