mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 12:40:01 +01:00
MDL-23545 question: XML import/export add category description
This commit is contained in:
parent
674ef9baac
commit
1dab8faafd
@ -76,7 +76,7 @@ function get_questions_category( $category, $noparent=false, $recurse=true, $exp
|
||||
|
||||
// Get the list of questions for the category
|
||||
list($usql, $params) = $DB->get_in_or_equal($categorylist);
|
||||
$questions = $DB->get_records_select('question', "category {$usql} {$npsql}", $params, 'qtype, name');
|
||||
$questions = $DB->get_records_select('question', "category {$usql} {$npsql}", $params, 'category, qtype, name');
|
||||
|
||||
// Iterate through questions, getting stuff we need
|
||||
$qresults = array();
|
||||
|
@ -52,6 +52,8 @@ class qformat_default {
|
||||
public $translator = null;
|
||||
public $canaccessbackupdata = true;
|
||||
protected $importcontext = null;
|
||||
/** @var bool $displayprogress Whether to display progress. */
|
||||
public $displayprogress = true;
|
||||
|
||||
// functions to indicate import/export functionality
|
||||
// override to return true if implemented
|
||||
@ -210,6 +212,17 @@ class qformat_default {
|
||||
$this->canaccessbackupdata = $canaccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change whether to display progress messages.
|
||||
* There is normally no need to use this function as the
|
||||
* default for $displayprogress is true.
|
||||
* Set to false for unit tests.
|
||||
* @param bool $displayprogress
|
||||
*/
|
||||
public function set_display_progress($displayprogress) {
|
||||
$this->displayprogress = $displayprogress;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* IMPORTING FUNCTIONS
|
||||
***********************/
|
||||
@ -292,7 +305,9 @@ class qformat_default {
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
// STAGE 1: Parse the file
|
||||
echo $OUTPUT->notification(get_string('parsingquestions', 'question'), 'notifysuccess');
|
||||
if ($this->displayprogress) {
|
||||
echo $OUTPUT->notification(get_string('parsingquestions', 'question'), 'notifysuccess');
|
||||
}
|
||||
|
||||
if (! $lines = $this->readdata($this->filename)) {
|
||||
echo $OUTPUT->notification(get_string('cannotread', 'question'));
|
||||
@ -305,8 +320,10 @@ class qformat_default {
|
||||
}
|
||||
|
||||
// STAGE 2: Write data to database
|
||||
echo $OUTPUT->notification(get_string('importingquestions', 'question',
|
||||
$this->count_questions($questions)), 'notifysuccess');
|
||||
if ($this->displayprogress) {
|
||||
echo $OUTPUT->notification(get_string('importingquestions', 'question',
|
||||
$this->count_questions($questions)), 'notifysuccess');
|
||||
}
|
||||
|
||||
// check for errors before we continue
|
||||
if ($this->stoponerror and ($this->importerrors>0)) {
|
||||
@ -366,7 +383,7 @@ class qformat_default {
|
||||
if ($this->catfromfile) {
|
||||
// find/create category object
|
||||
$catpath = $question->category;
|
||||
$newcategory = $this->create_category_path($catpath);
|
||||
$newcategory = $this->create_category_path($catpath, $question);
|
||||
if (!empty($newcategory)) {
|
||||
$this->category = $newcategory;
|
||||
}
|
||||
@ -378,7 +395,9 @@ class qformat_default {
|
||||
|
||||
$count++;
|
||||
|
||||
echo "<hr /><p><b>{$count}</b>. ".$this->format_question_text($question)."</p>";
|
||||
if ($this->displayprogress) {
|
||||
echo "<hr /><p><b>{$count}</b>. " . $this->format_question_text($question) . "</p>";
|
||||
}
|
||||
|
||||
$question->category = $this->category->id;
|
||||
$question->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
|
||||
@ -502,10 +521,10 @@ class qformat_default {
|
||||
* but if $getcontext is set then ignore the context and use selected category context.
|
||||
*
|
||||
* @param string catpath delimited category path
|
||||
* @param int courseid course to search for categories
|
||||
* @param object $lastcategoryinfo Contains category information
|
||||
* @return mixed category object or null if fails
|
||||
*/
|
||||
protected function create_category_path($catpath) {
|
||||
protected function create_category_path($catpath, $lastcategoryinfo = null) {
|
||||
global $DB;
|
||||
$catnames = $this->split_category_path($catpath);
|
||||
$parent = 0;
|
||||
@ -535,27 +554,47 @@ class qformat_default {
|
||||
$this->importcontext = $context;
|
||||
|
||||
// Now create any categories that need to be created.
|
||||
foreach ($catnames as $catname) {
|
||||
foreach ($catnames as $key => $catname) {
|
||||
if ($parent == 0) {
|
||||
$category = question_get_top_category($context->id, true);
|
||||
$parent = $category->id;
|
||||
} else if ($category = $DB->get_record('question_categories',
|
||||
array('name' => $catname, 'contextid' => $context->id, 'parent' => $parent))) {
|
||||
// Do nothing unless the child category appears before the parent category
|
||||
// in the imported xml file. Because the parent was created without info being available
|
||||
// at that time, this allows the info to be added from the xml data.
|
||||
if ($key == (count($catnames) - 1) && $lastcategoryinfo && $lastcategoryinfo->info !== null &&
|
||||
$lastcategoryinfo->info !== "" && $category->info == "") {
|
||||
$category->info = $lastcategoryinfo->info;
|
||||
if ($lastcategoryinfo->infoformat !== null && $lastcategoryinfo->infoformat !== "") {
|
||||
$category->infoformat = $lastcategoryinfo->infoformat;
|
||||
}
|
||||
$DB->update_record('question_categories', $category);
|
||||
}
|
||||
$parent = $category->id;
|
||||
} else {
|
||||
if ($catname == 'top') {
|
||||
// Should not happen, but if it does just move on.
|
||||
// Occurs when there has been some import/export that has created
|
||||
// multiple nested 'top' categories (due to old bug solved by MDL-63165).
|
||||
// Not throwing an error here helps clean up old errors (silently).
|
||||
// This basically silently cleans up old errors. Not throwing an exception here.
|
||||
continue;
|
||||
}
|
||||
require_capability('moodle/question:managecategory', $context);
|
||||
// create the new category
|
||||
// Create the new category. This will create all the categories in the catpath,
|
||||
// though only the final category will have any info added if available.
|
||||
$category = new stdClass();
|
||||
$category->contextid = $context->id;
|
||||
$category->name = $catname;
|
||||
$category->info = '';
|
||||
// Only add info (category description) for the final category in the catpath.
|
||||
if ($key == (count($catnames) - 1) && $lastcategoryinfo && $lastcategoryinfo->info !== null &&
|
||||
$lastcategoryinfo->info !== "") {
|
||||
$category->info = $lastcategoryinfo->info;
|
||||
if ($lastcategoryinfo->infoformat !== null && $lastcategoryinfo->infoformat !== "") {
|
||||
$category->infoformat = $lastcategoryinfo->infoformat;
|
||||
}
|
||||
}
|
||||
$category->parent = $parent;
|
||||
$category->sortorder = 999;
|
||||
$category->stamp = make_unique_id_code();
|
||||
@ -832,14 +871,6 @@ class qformat_default {
|
||||
// Array of categories written to file.
|
||||
$writtencategories = [];
|
||||
|
||||
foreach ($parents as $parent) {
|
||||
$categoryname = $this->get_category_path($parent, $this->contexttofile);
|
||||
// Create 'dummy' question for category export.
|
||||
$dummyquestion = $this->create_dummy_question_representing_category($categoryname);
|
||||
$expout .= $this->writequestion($dummyquestion) . "\n";
|
||||
$writtencategories[] = $parent;
|
||||
}
|
||||
|
||||
foreach ($questions as $question) {
|
||||
// used by file api
|
||||
$contextid = $DB->get_field('question_categories', 'contextid',
|
||||
@ -862,7 +893,6 @@ class qformat_default {
|
||||
if ($question->category != $trackcategory) {
|
||||
$addnewcat = true;
|
||||
$trackcategory = $question->category;
|
||||
$categoryname = $this->get_category_path($trackcategory, $this->contexttofile);
|
||||
}
|
||||
$trackcategoryparents = question_categorylist_parents($trackcategory);
|
||||
// Check if we need to record empty parents categories.
|
||||
@ -872,17 +902,23 @@ class qformat_default {
|
||||
// If parent is empty.
|
||||
if (!count($DB->get_records('question', array('category' => $trackcategoryparent)))) {
|
||||
$categoryname = $this->get_category_path($trackcategoryparent, $this->contexttofile);
|
||||
// Create 'dummy' question for parent category.
|
||||
$dummyquestion = $this->create_dummy_question_representing_category($categoryname);
|
||||
$expout .= $this->writequestion($dummyquestion) . "\n";
|
||||
$writtencategories[] = $trackcategoryparent;
|
||||
$categoryinfo = $DB->get_record('question_categories', array('id' => $trackcategoryparent),
|
||||
'name, info, infoformat', MUST_EXIST);
|
||||
if ($categoryinfo->name != 'top') {
|
||||
// Create 'dummy' question for parent category.
|
||||
$dummyquestion = $this->create_dummy_question_representing_category($categoryname, $categoryinfo);
|
||||
$expout .= $this->writequestion($dummyquestion) . "\n";
|
||||
$writtencategories[] = $trackcategoryparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($addnewcat && !in_array($trackcategory, $writtencategories)) {
|
||||
$categoryname = $this->get_category_path($trackcategory, $this->contexttofile);
|
||||
$categoryinfo = $DB->get_record('question_categories', array('id' => $trackcategory),
|
||||
'info, infoformat', MUST_EXIST);
|
||||
// Create 'dummy' question for category.
|
||||
$dummyquestion = $this->create_dummy_question_representing_category($categoryname);
|
||||
$dummyquestion = $this->create_dummy_question_representing_category($categoryname, $categoryinfo);
|
||||
$expout .= $this->writequestion($dummyquestion) . "\n";
|
||||
$writtencategories[] = $trackcategory;
|
||||
}
|
||||
@ -913,15 +949,18 @@ class qformat_default {
|
||||
/**
|
||||
* Create 'dummy' question for category export.
|
||||
* @param string $categoryname the name of the category
|
||||
* @param object $categoryinfo description of the category
|
||||
* @return stdClass 'dummy' question for category
|
||||
*/
|
||||
protected function create_dummy_question_representing_category(string $categoryname) {
|
||||
protected function create_dummy_question_representing_category(string $categoryname, $categoryinfo) {
|
||||
$dummyquestion = new stdClass();
|
||||
$dummyquestion->qtype = 'category';
|
||||
$dummyquestion->category = $categoryname;
|
||||
$dummyquestion->id = 0;
|
||||
$dummyquestion->questiontextformat = '';
|
||||
$dummyquestion->contextid = 0;
|
||||
$dummyquestion->info = $categoryinfo->info;
|
||||
$dummyquestion->infoformat = $categoryinfo->infoformat;
|
||||
$dummyquestion->name = 'Switch category to ' . $categoryname;
|
||||
return $dummyquestion;
|
||||
}
|
||||
|
@ -33,4 +33,4 @@ Feature: Test importing questions from GIFT format.
|
||||
And I follow "Export"
|
||||
And I set the field "id_format_gift" to "1"
|
||||
And I press "Export questions to file"
|
||||
And following "click here" should download between "1650" and "1800" bytes
|
||||
And following "click here" should download between "1600" and "1800" bytes
|
||||
|
@ -1,5 +1,20 @@
|
||||
This files describes API changes for question import/export format plugins.
|
||||
|
||||
=== 3.6 ===
|
||||
|
||||
* Saving question category descriptions (info) is now supported in Moodle XML import/export format.
|
||||
New xml-structure snippet for a question category:
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>${$contexttypename}$/{$category_path}</text>
|
||||
</category>
|
||||
<info format="{$format}">
|
||||
<text>{$info_categorydescription}</text>
|
||||
</info>
|
||||
</question>
|
||||
* The method importprocess() in question/format.php no longer accepts $category as a parameter.
|
||||
If required in a plugin then please override this method.
|
||||
|
||||
=== 2.3 ===
|
||||
|
||||
* This plugin type now supports cron in the standard way. If required, Create a
|
||||
|
@ -63,6 +63,7 @@ class qformat_xml extends qformat_default {
|
||||
/**
|
||||
* Translate human readable format name
|
||||
* into internal Moodle code number
|
||||
* Note the reverse function is called get_format.
|
||||
* @param string name format name from xml file
|
||||
* @return int Moodle format code
|
||||
*/
|
||||
@ -909,12 +910,20 @@ class qformat_xml extends qformat_default {
|
||||
* import category. The format is:
|
||||
* <question type="category">
|
||||
* <category>tom/dick/harry</category>
|
||||
* <info format="moodle_auto_format"><text>Category description</text></info>
|
||||
* </question>
|
||||
*/
|
||||
protected function import_category($question) {
|
||||
$qo = new stdClass();
|
||||
$qo->qtype = 'category';
|
||||
$qo->category = $this->import_text($question['#']['category'][0]['#']['text']);
|
||||
$qo->info = '';
|
||||
$qo->infoformat = FORMAT_MOODLE;
|
||||
if (array_key_exists('info', $question['#'])) {
|
||||
$qo->info = $this->import_text($question['#']['info'][0]['#']['text']);
|
||||
// The import should have the format in human readable form, so translate to machine readable format.
|
||||
$qo->infoformat = $this->trans_format($question['#']['info'][0]['@']['format']);
|
||||
}
|
||||
return $qo;
|
||||
}
|
||||
|
||||
@ -1176,10 +1185,15 @@ class qformat_xml extends qformat_default {
|
||||
// Categories are a special case.
|
||||
if ($question->qtype == 'category') {
|
||||
$categorypath = $this->writetext($question->category);
|
||||
$categoryinfo = $this->writetext($question->info);
|
||||
$infoformat = $this->format($question->infoformat);
|
||||
$expout .= " <question type=\"category\">\n";
|
||||
$expout .= " <category>\n";
|
||||
$expout .= " {$categorypath}\n";
|
||||
$expout .= " {$categorypath}";
|
||||
$expout .= " </category>\n";
|
||||
$expout .= " <info {$infoformat}>\n";
|
||||
$expout .= " {$categoryinfo}";
|
||||
$expout .= " </info>\n";
|
||||
$expout .= " </question>\n";
|
||||
return $expout;
|
||||
}
|
||||
|
84
question/format/xml/tests/fixtures/categories_reverse_order.xml
vendored
Normal file
84
question/format/xml/tests/fixtures/categories_reverse_order.xml
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Sigma/Tau</text>
|
||||
</category>
|
||||
<info format="html">
|
||||
<text>This is Tau category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 106 -->
|
||||
<question type="essay">
|
||||
<name>
|
||||
<text>Tau Question</text>
|
||||
</name>
|
||||
<questiontext format="moodle_auto_format">
|
||||
<text>Testing Tau Question</text>
|
||||
</questiontext>
|
||||
<generalfeedback format="moodle_auto_format">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>0.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<responseformat>editor</responseformat>
|
||||
<responserequired>1</responserequired>
|
||||
<responsefieldlines>15</responsefieldlines>
|
||||
<attachments>0</attachments>
|
||||
<attachmentsrequired>0</attachmentsrequired>
|
||||
<graderinfo format="html">
|
||||
<text></text>
|
||||
</graderinfo>
|
||||
<responsetemplate format="html">
|
||||
<text></text>
|
||||
</responsetemplate>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Sigma</text>
|
||||
</category>
|
||||
<info format="html">
|
||||
<text>This is Sigma category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 105 -->
|
||||
<question type="shortanswer">
|
||||
<name>
|
||||
<text>Sigma Question</text>
|
||||
</name>
|
||||
<questiontext format="moodle_auto_format">
|
||||
<text>Testing Sigma Question</text>
|
||||
</questiontext>
|
||||
<generalfeedback format="moodle_auto_format">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>0.3333333</penalty>
|
||||
<hidden>0</hidden>
|
||||
<usecase>0</usecase>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>yes</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>no</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>may be</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
40
question/format/xml/tests/fixtures/category_with_description.xml
vendored
Normal file
40
question/format/xml/tests/fixtures/category_with_description.xml
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Alpha</text>
|
||||
</category>
|
||||
<info format="moodle_auto_format">
|
||||
<text>This is Alpha category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 91 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Alpha Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Alpha Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
41
question/format/xml/tests/fixtures/export_category.xml
vendored
Normal file
41
question/format/xml/tests/fixtures/export_category.xml
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Alpha</text>
|
||||
</category>
|
||||
|
||||
<info format="moodle_auto_format">
|
||||
<text>This is Alpha category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 91 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Alpha Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Alpha Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
60
question/format/xml/tests/fixtures/nested_categories.xml
vendored
Normal file
60
question/format/xml/tests/fixtures/nested_categories.xml
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Delta</text>
|
||||
</category>
|
||||
<info format="plain_text">
|
||||
<text>This is Delta category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Delta/Epsilon</text>
|
||||
</category>
|
||||
<info format="markdown">
|
||||
<text>This is Epsilon category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Delta/Epsilon/Zeta</text>
|
||||
</category>
|
||||
<info format="moodle_auto_format">
|
||||
<text>This is Zeta category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 93 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Zeta Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Zeta Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
181
question/format/xml/tests/fixtures/nested_categories_with_questions.xml
vendored
Normal file
181
question/format/xml/tests/fixtures/nested_categories_with_questions.xml
vendored
Normal file
@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Iota</text>
|
||||
</category>
|
||||
<info format="plain_text">
|
||||
<text>This is Iota category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 96 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Iota Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Iota Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Iota/Kappa</text>
|
||||
</category>
|
||||
<info format="markdown">
|
||||
<text>This is Kappa category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 106 -->
|
||||
<question type="essay">
|
||||
<name>
|
||||
<text>Kappa Essay Question</text>
|
||||
</name>
|
||||
<questiontext format="moodle_auto_format">
|
||||
<text>Testing Kappa Essay Question</text>
|
||||
</questiontext>
|
||||
<generalfeedback format="moodle_auto_format">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>0.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<responseformat>editor</responseformat>
|
||||
<responserequired>1</responserequired>
|
||||
<responsefieldlines>10</responsefieldlines>
|
||||
<attachments>0</attachments>
|
||||
<attachmentsrequired>0</attachmentsrequired>
|
||||
<graderinfo format="html">
|
||||
<text></text>
|
||||
</graderinfo>
|
||||
<responsetemplate format="html">
|
||||
<text></text>
|
||||
</responsetemplate>
|
||||
</question>
|
||||
|
||||
<!-- question: 97 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Kappa Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Kappa Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Iota/Kappa/Lambda</text>
|
||||
</category>
|
||||
<info format="moodle_auto_format">
|
||||
<text>This is Lambda category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 98 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Lambda Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Lambda Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Iota/Mu</text>
|
||||
</category>
|
||||
<info format="moodle_auto_format">
|
||||
<text>This is Mu category for test</text>
|
||||
</info>
|
||||
</question>
|
||||
|
||||
<!-- question: 99 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Mu Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Mu Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
72
question/format/xml/tests/fixtures/old_format_file.xml
vendored
Normal file
72
question/format/xml/tests/fixtures/old_format_file.xml
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<quiz>
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Pi</text>
|
||||
</category>
|
||||
</question>
|
||||
|
||||
<!-- question: 103 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Pi Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Pi Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
|
||||
<!-- question: 0 -->
|
||||
<question type="category">
|
||||
<category>
|
||||
<text>$course$/Pi/Rho</text>
|
||||
</category>
|
||||
</question>
|
||||
|
||||
<!-- question: 104 -->
|
||||
<question type="truefalse">
|
||||
<name>
|
||||
<text>Rho Question</text>
|
||||
</name>
|
||||
<questiontext format="html">
|
||||
<text><![CDATA[<p>Testing Rho Question</p>]]></text>
|
||||
</questiontext>
|
||||
<generalfeedback format="html">
|
||||
<text></text>
|
||||
</generalfeedback>
|
||||
<defaultgrade>1.0000000</defaultgrade>
|
||||
<penalty>1.0000000</penalty>
|
||||
<hidden>0</hidden>
|
||||
<answer fraction="100" format="moodle_auto_format">
|
||||
<text>true</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
<answer fraction="0" format="moodle_auto_format">
|
||||
<text>false</text>
|
||||
<feedback format="html">
|
||||
<text></text>
|
||||
</feedback>
|
||||
</answer>
|
||||
</question>
|
||||
</quiz>
|
427
question/format/xml/tests/qformat_xml_import_export_test.php
Normal file
427
question/format/xml/tests/qformat_xml_import_export_test.php
Normal file
@ -0,0 +1,427 @@
|
||||
<?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 export/import description (info) for question category in the Moodle XML format.
|
||||
*
|
||||
* @package qformat_xml
|
||||
* @copyright 2014 Nikita Nikitsky, Volgograd State Technical University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->dirroot . '/question/format/xml/format.php');
|
||||
require_once($CFG->dirroot . '/question/format.php');
|
||||
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
|
||||
require_once($CFG->dirroot . '/question/editlib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for the XML question format import and export.
|
||||
*
|
||||
* @copyright 2014 Nikita Nikitsky, Volgograd State Technical University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qformat_xml_import_export_test extends advanced_testcase {
|
||||
/**
|
||||
* Create object qformat_xml for test.
|
||||
* @param string $filename with name for testing file.
|
||||
* @param object $course
|
||||
* @return object qformat_xml.
|
||||
*/
|
||||
public function create_qformat($filename, $course) {
|
||||
global $DB;
|
||||
$qformat = new qformat_xml();
|
||||
$contexts = $DB->get_records('context');
|
||||
$importfile = __DIR__ . '/fixtures/' .$filename;
|
||||
$realfilename = $filename;
|
||||
$qformat->setContexts($contexts);
|
||||
$qformat->setCourse($course);
|
||||
$qformat->setFilename($importfile);
|
||||
$qformat->setRealfilename($realfilename);
|
||||
$qformat->setMatchgrades('error');
|
||||
$qformat->setCatfromfile(1);
|
||||
$qformat->setContextfromfile(1);
|
||||
$qformat->setStoponerror(1);
|
||||
$qformat->setCattofile(1);
|
||||
$qformat->setContexttofile(1);
|
||||
$qformat->set_display_progress(false);
|
||||
|
||||
return $qformat;
|
||||
}
|
||||
/**
|
||||
* Check xml for compliance.
|
||||
* @param string $expectedxml with correct string.
|
||||
* @param string $xml you want to check.
|
||||
*/
|
||||
public function assert_same_xml($expectedxml, $xml) {
|
||||
$this->assertEquals(preg_replace('/( +)/', "", str_replace("\n", "",
|
||||
str_replace("\r\n", "\n", str_replace("\t", "\n", $expectedxml)))),
|
||||
preg_replace('/( +)/', "", str_replace("\n", "",
|
||||
str_replace( "\r\n", "\n", str_replace( "\t", "\n", $xml)))));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check xml for compliance.
|
||||
* @param string $expectedxml with correct string.
|
||||
* @param string $xml you want to check.
|
||||
*/
|
||||
public function assert_same_xml_random_category($expectedxml, $xml) {
|
||||
$str1 = preg_replace('/( +)/', "",
|
||||
str_replace("\n", "", str_replace("\r\n", "\n",
|
||||
str_replace("\t", "\n", $expectedxml))));
|
||||
|
||||
$str2 = preg_replace('/( +)/', "", str_replace("\n", "",
|
||||
str_replace( "\r\n", "\n", str_replace( "\t", "\n", $xml))));
|
||||
|
||||
$str1 = str_replace("unknownhost+" + '/[0-9]+/' + "+", "", $str1);
|
||||
$this->assertEquals($str1, $str2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check imported category.
|
||||
* @param string $name imported category name.
|
||||
* @param string $info imported category info field (description of category).
|
||||
* @param int $infoformat imported category info field format.
|
||||
*/
|
||||
public function assert_category_imported($name, $info, $infoformat) {
|
||||
global $DB;
|
||||
$category = $DB->get_record('question_categories', ['name' => $name], '*', MUST_EXIST);
|
||||
$this->assertEquals($info, $category->info);
|
||||
$this->assertEquals($infoformat, $category->infoformat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a question category has a given parent.
|
||||
* @param string $catname Name of the question category
|
||||
* @param string $parentname Name of the parent category
|
||||
* @throws dml_exception
|
||||
*/
|
||||
public function assert_category_has_parent($catname, $parentname) {
|
||||
global $DB;
|
||||
$sql = 'SELECT qc1.*
|
||||
FROM {question_categories} qc1
|
||||
JOIN {question_categories} qc2 ON qc1.parent = qc2.id
|
||||
WHERE qc1.name = ?
|
||||
AND qc2.name = ?';
|
||||
$categories = $DB->get_records_sql($sql, [$catname, $parentname]);
|
||||
$this->assertTrue(count($categories) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a question exists in a category.
|
||||
* @param string $qname The name of the question
|
||||
* @param string $catname The name of the category
|
||||
* @throws dml_exception
|
||||
*/
|
||||
public function assert_question_in_category($qname, $catname) {
|
||||
global $DB;
|
||||
$question = $DB->get_record('question', ['name' => $qname], '*', MUST_EXIST);
|
||||
$category = $DB->get_record('question_categories', ['name' => $catname], '*', MUST_EXIST);
|
||||
$this->assertEquals($category->id, $question->category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple check for importing a category with a description.
|
||||
*/
|
||||
public function test_import_category() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$qformat = $this->create_qformat('category_with_description.xml', $course);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Alpha', 'This is Alpha category for test', FORMAT_MOODLE);
|
||||
$this->assert_category_has_parent('Alpha', 'top');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check importing nested categories.
|
||||
*/
|
||||
public function test_import_nested_categories() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$qformat = $this->create_qformat('nested_categories.xml', $course);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Delta', 'This is Delta category for test', FORMAT_PLAIN);
|
||||
$this->assert_category_imported('Epsilon', 'This is Epsilon category for test', FORMAT_MARKDOWN);
|
||||
$this->assert_category_imported('Zeta', 'This is Zeta category for test', FORMAT_MOODLE);
|
||||
$this->assert_category_has_parent('Delta', 'top');
|
||||
$this->assert_category_has_parent('Epsilon', 'Delta');
|
||||
$this->assert_category_has_parent('Zeta', 'Epsilon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check importing nested categories contain the right questions.
|
||||
*/
|
||||
public function test_import_nested_categories_with_questions() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$qformat = $this->create_qformat('nested_categories_with_questions.xml', $course);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Iota', 'This is Iota category for test', FORMAT_PLAIN);
|
||||
$this->assert_category_imported('Kappa', 'This is Kappa category for test', FORMAT_MARKDOWN);
|
||||
$this->assert_category_imported('Lambda', 'This is Lambda category for test', FORMAT_MOODLE);
|
||||
$this->assert_category_imported('Mu', 'This is Mu category for test', FORMAT_MOODLE);
|
||||
$this->assert_question_in_category('Iota Question', 'Iota');
|
||||
$this->assert_question_in_category('Kappa Question', 'Kappa');
|
||||
$this->assert_question_in_category('Lambda Question', 'Lambda');
|
||||
$this->assert_question_in_category('Mu Question', 'Mu');
|
||||
$this->assert_category_has_parent('Iota', 'top');
|
||||
$this->assert_category_has_parent('Kappa', 'Iota');
|
||||
$this->assert_category_has_parent('Lambda', 'Kappa');
|
||||
$this->assert_category_has_parent('Mu', 'Iota');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check import of an old file (without format), for backward compatability.
|
||||
*/
|
||||
public function test_import_old_format() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$qformat = $this->create_qformat('old_format_file.xml', $course);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Pi', '', FORMAT_MOODLE);
|
||||
$this->assert_category_imported('Rho', '', FORMAT_MOODLE);
|
||||
$this->assert_question_in_category('Pi Question', 'Pi');
|
||||
$this->assert_question_in_category('Rho Question', 'Rho');
|
||||
$this->assert_category_has_parent('Pi', 'top');
|
||||
$this->assert_category_has_parent('Rho', 'Pi');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the import of an xml file where the child category exists before the parent category.
|
||||
*/
|
||||
public function test_import_categories_in_reverse_order() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$qformat = $this->create_qformat('categories_reverse_order.xml', $course);
|
||||
$imported = $qformat->importprocess();
|
||||
$this->assertTrue($imported);
|
||||
$this->assert_category_imported('Sigma', 'This is Sigma category for test', FORMAT_HTML);
|
||||
$this->assert_category_imported('Tau', 'This is Tau category for test', FORMAT_HTML);
|
||||
$this->assert_question_in_category('Sigma Question', 'Sigma');
|
||||
$this->assert_question_in_category('Tau Question', 'Tau');
|
||||
$this->assert_category_has_parent('Sigma', 'top');
|
||||
$this->assert_category_has_parent('Tau', 'Sigma');
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple check for exporting a category.
|
||||
*/
|
||||
public function test_export_category() {
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
// Note while this loads $qformat with all the 'right' data from the xml file,
|
||||
// the call to setCategory, followed by exportprocess will actually only export data
|
||||
// from the database (created by the generator).
|
||||
$qformat = $this->create_qformat('export_category.xml', $course);
|
||||
|
||||
$category = $generator->create_question_category([
|
||||
'name' => 'Alpha',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Alpha category for test',
|
||||
'infoformat' => '0',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => '0',
|
||||
'sortorder' => '999']);
|
||||
$question = $generator->create_question('truefalse', null, [
|
||||
'category' => $category->id,
|
||||
'name' => 'AlphaQuestion',
|
||||
'questiontext' => ['format' => '1', 'text' => '<p>TestingAlphaQuestion</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$qformat->setCategory($category);
|
||||
|
||||
$xml = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '', $qformat->exportprocess());
|
||||
$file = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '',
|
||||
file_get_contents(__DIR__ . '/fixtures/export_category.xml'));
|
||||
$this->assert_same_xml($file, $xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check exporting nested categories.
|
||||
*/
|
||||
public function test_export_nested_categories() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$qformat = $this->create_qformat('nested_categories.zml', $course);
|
||||
|
||||
$categorydelta = $generator->create_question_category([
|
||||
'name' => 'Delta',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Delta category for test',
|
||||
'infoformat' => '2',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => '0',
|
||||
'sortorder' => '999']);
|
||||
$categoryepsilon = $generator->create_question_category([
|
||||
'name' => 'Epsilon',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Epsilon category for test',
|
||||
'infoformat' => '4',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => $categorydelta->id,
|
||||
'sortorder' => '999']);
|
||||
$categoryzeta = $generator->create_question_category([
|
||||
'name' => 'Zeta',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Zeta category for test',
|
||||
'infoformat' => '0',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => $categoryepsilon->id,
|
||||
'sortorder' => '999']);
|
||||
$question = $generator->create_question('truefalse', null, [
|
||||
'category' => $categoryzeta->id,
|
||||
'name' => 'Zeta Question',
|
||||
'questiontext' => [
|
||||
'format' => '1',
|
||||
'text' => '<p>Testing Zeta Question</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$qformat->setCategory($categorydelta);
|
||||
$qformat->setCategory($categoryepsilon);
|
||||
$qformat->setCategory($categoryzeta);
|
||||
|
||||
$xml = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '', $qformat->exportprocess());
|
||||
$file = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '',
|
||||
file_get_contents(__DIR__ . '/fixtures/nested_categories.xml'));
|
||||
$this->assert_same_xml($file, $xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check exporting nested categories contain the right questions.
|
||||
*/
|
||||
public function test_export_nested_categories_with_questions() {
|
||||
$this->resetAfterTest(true);
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->setAdminUser();
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
|
||||
$qformat = $this->create_qformat('nested_categories_with_questions.xml', $course);
|
||||
|
||||
$categoryiota = $generator->create_question_category([
|
||||
'name' => 'Iota',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Iota category for test',
|
||||
'infoformat' => '2',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => '0',
|
||||
'sortorder' => '999']);
|
||||
$iotaquestion = $generator->create_question('truefalse', null, [
|
||||
'category' => $categoryiota->id,
|
||||
'name' => 'Iota Question',
|
||||
'questiontext' => [
|
||||
'format' => '1',
|
||||
'text' => '<p>Testing Iota Question</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$categorykappa = $generator->create_question_category([
|
||||
'name' => 'Kappa',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Kappa category for test',
|
||||
'infoformat' => '4',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => $categoryiota->id,
|
||||
'sortorder' => '999']);
|
||||
$kappaquestion = $generator->create_question('essay', null, [
|
||||
'category' => $categorykappa->id,
|
||||
'name' => 'Kappa Essay Question',
|
||||
'questiontext' => ['text' => 'Testing Kappa Essay Question'],
|
||||
'generalfeedback' => '',
|
||||
'responseformat' => 'editor',
|
||||
'responserequired' => 1,
|
||||
'responsefieldlines' => 10,
|
||||
'attachments' => 0,
|
||||
'attachmentsrequired' => 0,
|
||||
'graderinfo' => ['format' => '1', 'text' => ''],
|
||||
'responsetemplate' => ['format' => '1', 'text' => ''],
|
||||
]);
|
||||
$kappaquestion1 = $generator->create_question('truefalse', null, [
|
||||
'category' => $categorykappa->id,
|
||||
'name' => 'Kappa Question',
|
||||
'questiontext' => [
|
||||
'format' => '1',
|
||||
'text' => '<p>Testing Kappa Question</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$categorylambda = $generator->create_question_category([
|
||||
'name' => 'Lambda',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Lambda category for test',
|
||||
'infoformat' => '0',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => $categorykappa->id,
|
||||
'sortorder' => '999']);
|
||||
$lambdaquestion = $generator->create_question('truefalse', null, [
|
||||
'category' => $categorylambda->id,
|
||||
'name' => 'Lambda Question',
|
||||
'questiontext' => [
|
||||
'format' => '1',
|
||||
'text' => '<p>Testing Lambda Question</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$categorymu = $generator->create_question_category([
|
||||
'name' => 'Mu',
|
||||
'contextid' => '2',
|
||||
'info' => 'This is Mu category for test',
|
||||
'infoformat' => '0',
|
||||
'stamp' => make_unique_id_code(),
|
||||
'parent' => $categoryiota->id,
|
||||
'sortorder' => '999']);
|
||||
$muquestion = $generator->create_question('truefalse', null, [
|
||||
'category' => $categorymu->id,
|
||||
'name' => 'Mu Question',
|
||||
'questiontext' => [
|
||||
'format' => '1',
|
||||
'text' => '<p>Testing Mu Question</p>'],
|
||||
'generalfeedback' => ['format' => '1', 'text' => ''],
|
||||
'correctanswer' => '1',
|
||||
'feedbacktrue' => ['format' => '1', 'text' => ''],
|
||||
'feedbackfalse' => ['format' => '1', 'text' => ''],
|
||||
'penalty' => '1']);
|
||||
$qformat->setCategory($categoryiota);
|
||||
|
||||
$xml = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '', $qformat->exportprocess());
|
||||
$file = preg_replace('/(<!-- question: )([0-9]+)( -->)/', '',
|
||||
file_get_contents(__DIR__ . '/fixtures/nested_categories_with_questions.xml'));
|
||||
$this->assert_same_xml($file, $xml);
|
||||
}
|
||||
}
|
@ -1583,4 +1583,40 @@ END;
|
||||
$this->assertEquals('/myfolder/', $file->filepath);
|
||||
$this->assertEquals(6, $file->size);
|
||||
}
|
||||
|
||||
public function test_create_dummy_question() {
|
||||
|
||||
$testobject = new mock_qformat_xml();
|
||||
$categoryname = 'name1';
|
||||
$categoryinfo = new stdClass();
|
||||
$categoryinfo->info = 'info1';
|
||||
$categoryinfo->infoformat = 'infoformat1';
|
||||
$dummyquestion = $testobject->mock_create_dummy_question_representing_category($categoryname, $categoryinfo);
|
||||
|
||||
$this->assertEquals('category', $dummyquestion->qtype);
|
||||
$this->assertEquals($categoryname, $dummyquestion->category);
|
||||
$this->assertEquals($categoryinfo->info, $dummyquestion->info);
|
||||
$this->assertEquals($categoryinfo->infoformat, $dummyquestion->infoformat);
|
||||
$this->assertEquals('Switch category to ' . $categoryname, $dummyquestion->name);
|
||||
$this->assertEquals(0, $dummyquestion->id);
|
||||
$this->assertEquals('', $dummyquestion->questiontextformat);
|
||||
$this->assertEquals(0, $dummyquestion->contextid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class mock_qformat_xml exists only to enable testing of the create dummy question category.
|
||||
* @package qformat_xml
|
||||
* @copyright 2018 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mock_qformat_xml extends qformat_xml {
|
||||
/**
|
||||
* Make public an otherwise protected function.
|
||||
* @param string $categoryname the name of the category
|
||||
* @param object $categoryinfo description of the category
|
||||
*/
|
||||
public function mock_create_dummy_question_representing_category(string $categoryname, $categoryinfo) {
|
||||
return $this->create_dummy_question_representing_category($categoryname, $categoryinfo);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user