Merge branch 'MDL-61614-master' of git://github.com/rezaies/moodle

This commit is contained in:
Eloy Lafuente (stronk7)
2018-04-18 23:13:07 +02:00
16 changed files with 792 additions and 309 deletions
+3 -3
View File
@@ -136,7 +136,7 @@ class quiz {
public function preload_questions() {
$this->questions = question_preload_questions(null,
'slot.maxmark, slot.id AS slotid, slot.slot, slot.page,
slot.questioncategoryid AS randomfromcategory, slot.tags AS randomfromtags,
slot.questioncategoryid AS randomfromcategory,
slot.includingsubcategories AS randomincludingsubcategories',
'{quiz_slots} slot ON slot.quizid = :quizid AND q.id = slot.questionid',
array('quizid' => $this->quiz->id), 'slot.slot');
@@ -569,7 +569,7 @@ class quiz_attempt {
$this->quba = question_engine::load_questions_usage_by_activity($this->attempt->uniqueid);
$this->slots = $DB->get_records('quiz_slots',
array('quizid' => $this->get_quizid()), 'slot',
'slot, requireprevious, questionid, includingsubcategories, tags');
'slot, requireprevious, questionid, includingsubcategories');
$this->sections = array_values($DB->get_records('quiz_sections',
array('quizid' => $this->get_quizid()), 'firstslot'));
@@ -1874,7 +1874,7 @@ class quiz_attempt {
if ($questiondata->qtype != 'random') {
$newqusetionid = $questiondata->id;
} else {
$tagids = quiz_extract_random_question_tag_ids($this->slots[$slot]->tags);
$tagids = quiz_retrieve_slot_tag_ids($this->slots[$slot]->id);
$randomloader = new \core_question\bank\random_question_loader($qubaids, array());
$newqusetionid = $randomloader->get_next_question_id($questiondata->category,
@@ -58,7 +58,10 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
$qinstances = new backup_nested_element('question_instances');
$qinstance = new backup_nested_element('question_instance', array('id'), array(
'slot', 'page', 'requireprevious', 'questionid', 'questioncategoryid', 'includingsubcategories', 'tags', 'maxmark'));
'slot', 'page', 'requireprevious', 'questionid', 'questioncategoryid', 'includingsubcategories', 'maxmark'));
$qinstancetags = new backup_nested_element('tags');
$qinstancetag = new backup_nested_element('tag', array('id'), array('tagid', 'tagname'));
$sections = new backup_nested_element('sections');
@@ -98,6 +101,9 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
$quiz->add_child($qinstances);
$qinstances->add_child($qinstance);
$qinstance->add_child($qinstancetags);
$qinstancetags->add_child($qinstancetag);
$quiz->add_child($sections);
$sections->add_child($section);
@@ -119,6 +125,9 @@ class backup_quiz_activity_structure_step extends backup_questions_activity_stru
$qinstance->set_source_table('quiz_slots',
array('quizid' => backup::VAR_PARENTID));
$qinstancetag->set_source_table('quiz_slot_tags',
array('slotid' => backup::VAR_PARENTID));
$section->set_source_table('quiz_sections',
array('quizid' => backup::VAR_PARENTID));
@@ -59,6 +59,8 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
$paths[] = new restore_path_element('quiz_question_instance',
'/activity/quiz/question_instances/question_instance');
$paths[] = new restore_path_element('quiz_slot_tags',
'/activity/quiz/question_instances/question_instance/tags/tag');
$paths[] = new restore_path_element('quiz_section', '/activity/quiz/sections/section');
$paths[] = new restore_path_element('quiz_feedback', '/activity/quiz/feedbacks/feedback');
$paths[] = new restore_path_element('quiz_override', '/activity/quiz/overrides/override');
@@ -254,6 +256,7 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
global $CFG, $DB;
$data = (object)$data;
$oldid = $data->id;
// Backwards compatibility for old field names (MDL-43670).
if (!isset($data->questionid) && isset($data->question)) {
@@ -301,14 +304,32 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
$data->includingsubcategories = $questionmapping->info->questiontext ? 1 : 0;
}
if (isset($data->tags)) {
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
$newitemid = $DB->insert_record('quiz_slots', $data);
// Add mapping, restore of slot tags (for random questions) need it.
$this->set_mapping('quiz_question_instance', $oldid, $newitemid);
}
$tags = quiz_extract_random_question_tags($data->tags, $this->task->is_samesite());
$data->tags = quiz_build_random_question_tag_json($tags);
/**
* Process a quiz_slot_tags restore
*
* @param stdClass|array $data The quiz_slot_tags data
*/
protected function process_quiz_slot_tags($data) {
global $DB;
$data = (object)$data;
$data->slotid = $this->get_new_parentid('quiz_question_instance');
if ($this->task->is_samesite() && $tag = core_tag_tag::get($data->tagid, 'id, name')) {
$data->tagname = $tag->name;
} else if ($tag = core_tag_tag::get_by_name(0, $data->tagname, 'id, name')) {
$data->tagid = $tag->id;
} else {
$data->tagid = null;
$data->tagname = $tag->name;
}
$DB->insert_record('quiz_slots', $data);
$DB->insert_record('quiz_slot_tags', $data);
}
protected function process_quiz_section($data) {
@@ -43,6 +43,11 @@ class slot_random {
*/
protected $quiz = null;
/**
* @var \core_tag_tag[] List of tags for this slot.
*/
protected $tags = [];
/**
* slot_random constructor.
*
@@ -52,9 +57,8 @@ class slot_random {
$this->record = new \stdClass();
$properties = array(
'id', 'slot', 'quizid', 'page', 'requireprevious',
'questionid', 'questioncategoryid', 'includingsubcategories',
'tags', 'maxmark');
'id', 'slot', 'quizid', 'page', 'requireprevious', 'questionid',
'questioncategoryid', 'includingsubcategories', 'maxmark');
foreach ($properties as $property) {
if (isset($slotrecord->$property)) {
@@ -95,6 +99,29 @@ class slot_random {
$this->record->quizid = $quiz->id;
}
/**
* Set some tags for this quiz slot.
*
* @param \core_tag_tag[] $tags
*/
public function set_tags($tags) {
$this->tags = [];
foreach ($tags as $tag) {
// We use $tag->id as the key for the array so not only it handles duplicates of the same tag being given,
// but also it is consistent with the behaviour of set_tags_by_id() below.
$this->tags[$tag->id] = $tag;
}
}
/**
* Set some tags for this quiz slot. This function uses tag ids to find tags.
*
* @param int[] $tagids
*/
public function set_tags_by_id($tagids) {
$this->tags = \core_tag_tag::get_bulk($tagids, 'id, name');
}
/**
* Inserts the quiz slot at the $page page.
* It is required to call this function if you are building a quiz slot object from scratch.
@@ -151,6 +178,19 @@ class slot_random {
}
$this->record->id = $DB->insert_record('quiz_slots', $this->record);
if (!empty($this->tags)) {
$recordstoinsert = [];
foreach ($this->tags as $tag) {
$recordstoinsert[] = (object)[
'slotid' => $this->record->id,
'tagid' => $tag->id,
'tagname' => $tag->name
];
}
$DB->insert_records('quiz_slot_tags', $recordstoinsert);
}
$trans->allow_commit();
}
}
+1
View File
@@ -914,6 +914,7 @@ class structure {
$maxslot = $DB->get_field_sql('SELECT MAX(slot) FROM {quiz_slots} WHERE quizid = ?', array($this->get_quizid()));
$trans = $DB->start_delegated_transaction();
$DB->delete_records('quiz_slot_tags', array('slotid' => $slot->id));
$DB->delete_records('quiz_slots', array('id' => $slot->id));
for ($i = $slot->slot + 1; $i <= $maxslot; $i++) {
$DB->set_field('quiz_slots', 'slot', $i - 1,
Regular → Executable
+14 -2
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="mod/quiz/db" VERSION="20180207" COMMENT="XMLDB file for Moodle mod/quiz"
<XMLDB PATH="mod/quiz/db" VERSION="20180407" COMMENT="XMLDB file for Moodle mod/quiz"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
@@ -65,7 +65,6 @@
<FIELD NAME="questionid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Foreign key references question.id."/>
<FIELD NAME="questioncategoryid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The question category that the random question will be picked from. Will be null if and only if the question is not a random question."/>
<FIELD NAME="includingsubcategories" TYPE="int" LENGTH="4" NOTNULL="false" SEQUENCE="false" COMMENT="Whether the random question can be picked from sub categories or not. Will be null if questioncategoryid is null."/>
<FIELD NAME="tags" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Contains data about the tags that a question must have so that it can be selected for this slot. This field is an array in the form of [tagid,tagname] which is stored as JSON. Will be null if questioncategoryid is null."/>
<FIELD NAME="maxmark" TYPE="number" LENGTH="12" NOTNULL="true" DEFAULT="0" SEQUENCE="false" DECIMALS="7" COMMENT="How many marks this question contributes to quiz.sumgrades."/>
</FIELDS>
<KEYS>
@@ -186,5 +185,18 @@
<INDEX NAME="name" UNIQUE="true" FIELDS="name"/>
</INDEXES>
</TABLE>
<TABLE NAME="quiz_slot_tags" COMMENT="Stores data about the tags that a question must have so that it can be selected for a quiz slot (when having a random question by tags on that slot).">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="slotid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The quiz slot that this tag belong to"/>
<FIELD NAME="tagid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="tagname" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false" COMMENT="The tag name is to be stored as well, so we won't lose data if the tag is removed from Moodle (A tag with the same name might be added in future)."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="slotid" TYPE="foreign" FIELDS="slotid" REFTABLE="quiz_slots" REFFIELDS="id"/>
<KEY NAME="tagid" TYPE="foreign" FIELDS="tagid" REFTABLE="tag" REFFIELDS="id"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
+40 -7
View File
@@ -117,13 +117,6 @@ function xmldb_quiz_upgrade($oldversion) {
$dbman->add_field($table, $field);
}
// Define field tags to be added to quiz_slots.
$field = new xmldb_field('tags', XMLDB_TYPE_TEXT, null, null, null, null, null, 'includingsubcategories');
// Conditionally launch add field tags.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Quiz savepoint reached.
upgrade_mod_savepoint(true, 2018020700, 'quiz');
}
@@ -163,5 +156,45 @@ function xmldb_quiz_upgrade($oldversion) {
upgrade_mod_savepoint(true, 2018020701, 'quiz');
}
if ($oldversion < 2018040700) {
// Define field tags to be dropped from quiz_slots. This field was added earlier to master only.
$table = new xmldb_table('quiz_slots');
$field = new xmldb_field('tags');
// Conditionally launch drop field quizid.
if ($dbman->field_exists($table, $field)) {
$dbman->drop_field($table, $field);
}
// Quiz savepoint reached.
upgrade_mod_savepoint(true, 2018040700, 'quiz');
}
if ($oldversion < 2018040800) {
// Define table quiz_slot_tags to be created.
$table = new xmldb_table('quiz_slot_tags');
// Adding fields to table quiz_slot_tags.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('slotid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('tagid', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('tagname', XMLDB_TYPE_CHAR, '255', null, null, null, null);
// Adding keys to table quiz_slot_tags.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('slotid', XMLDB_KEY_FOREIGN, array('slotid'), 'quiz_slots', array('id'));
$table->add_key('tagid', XMLDB_KEY_FOREIGN, array('tagid'), 'tag', array('id'));
// Conditionally launch create table for quiz_slot_tags.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Quiz savepoint reached.
upgrade_mod_savepoint(true, 2018040800, 'quiz');
}
return true;
}
+37 -7
View File
@@ -78,11 +78,9 @@ $toform = fullclone($question);
$toform->category = "{$category->id},{$category->contextid}";
$toform->includesubcategories = $slot->includingsubcategories;
$toform->fromtags = array();
if ($slot->tags) {
$tags = quiz_extract_random_question_tags($slot->tags);
foreach ($tags as $tag) {
$toform->fromtags[] = "{$tag->id},{$tag->name}";
}
$currentslottags = quiz_retrieve_slot_tags($slot->id);
foreach ($currentslottags as $slottag) {
$toform->fromtags[] = "{$slottag->tagid},{$slottag->tagname}";
}
$toform->returnurl = $returnurl;
@@ -117,6 +115,8 @@ if ($mform->is_cancelled()) {
$slot->questioncategoryid = $fromform->category;
$slot->includingsubcategories = $fromform->includesubcategories;
$DB->update_record('quiz_slots', $slot);
$tags = [];
foreach ($fromform->fromtags as $tagstring) {
list($tagid, $tagname) = explode(',', $tagstring);
@@ -125,9 +125,39 @@ if ($mform->is_cancelled()) {
'name' => $tagname
];
}
$slot->tags = quiz_build_random_question_tag_json($tags);
$DB->update_record('quiz_slots', $slot);
$recordstokeep = [];
$recordstoinsert = [];
$searchableslottags = array_map(function($slottag) {
return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
}, $currentslottags);
foreach ($tags as $tag) {
if ($key = array_search(['tagid' => $tag->id, 'tagname' => $tag->name], $searchableslottags)) {
// If found, $key would be the id field in the quiz_slot_tags table.
// Therefore, there was no need to check !== false here.
$recordstokeep[] = $key;
} else {
$recordstoinsert[] = (object)[
'slotid' => $slot->id,
'tagid' => $tag->id,
'tagname' => $tag->name
];
}
}
// Now, delete the remaining records.
if (!empty($recordstokeep)) {
list($select, $params) = $DB->get_in_or_equal($recordstokeep, SQL_PARAMS_QM, 'param', false);
$DB->delete_records_select('quiz_slot_tags', "id $select", $params);
} else {
$DB->delete_records('quiz_slot_tags', array('slotid' => $slot->id));
}
// And now, insert the extra records if there is any.
if (!empty($recordstoinsert)) {
$DB->insert_records('quiz_slot_tags', $recordstoinsert);
}
// Purge this question from the cache.
question_bank::notify_question_edited($question->id);
+3 -1
View File
@@ -183,7 +183,9 @@ function quiz_delete_instance($id) {
WHERE slot.quizid = ? AND q.qtype = ?";
$questionids = $DB->get_fieldset_sql($sql, array($quiz->id, 'random'));
// We need to do this before we try and delete randoms, otherwise they would still be 'in use'.
// We need to do the following deletes before we try and delete randoms, otherwise they would still be 'in use'.
$quizslots = $DB->get_fieldset_select('quiz_slots', 'id', 'quizid = ?', array($quiz->id));
$DB->delete_records_list('quiz_slot_tags', 'slotid', $quizslots);
$DB->delete_records('quiz_slots', array('quizid' => $quiz->id));
$DB->delete_records('quiz_sections', array('quizid' => $quiz->id));
+42 -74
View File
@@ -208,7 +208,7 @@ function quiz_start_new_attempt($quizobj, $quba, $attempt, $attemptnumber, $time
continue;
}
$tagids = quiz_extract_random_question_tag_ids($questiondata->randomfromtags);
$tagids = quiz_retrieve_slot_tag_ids($questiondata->slotid);
// Deal with fixed random choices for testing.
if (isset($questionids[$quba->next_slot_number()])) {
@@ -2189,18 +2189,10 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
$catcontext = context::instance_by_id($category->contextid);
require_capability('moodle/question:useall', $catcontext);
$tags = [];
$tags = \core_tag_tag::get_bulk($tagids, 'id, name');
$tagstrings = [];
foreach ($tagids as $tagid) {
if ($tag = core_tag_tag::get($tagid, 'id,name')) {
$tags[] = [
'id' => $tagid,
'name' => $tag->name
];
$tagstrings[] = "{$tagid},{$tag->name}";
} else if (!empty($tagid)) {
print_error('invalidtagid', 'mod_quiz');
}
foreach ($tags as $tag) {
$tagstrings[] = "{$tag->id},{$tag->name}";
}
// Find existing random questions in this category that are
@@ -2239,11 +2231,11 @@ function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
$randomslotdata->questionid = $question->id;
$randomslotdata->questioncategoryid = $categoryid;
$randomslotdata->includingsubcategories = $includesubcategories ? 1 : 0;
$randomslotdata->tags = json_encode($tags);
$randomslotdata->maxmark = 1;
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
$randomslot->set_quiz($quiz);
$randomslot->set_tags($tags);
$randomslot->insert($addonpage);
}
}
@@ -2440,82 +2432,58 @@ function quiz_is_overriden_calendar_event(\calendar_event $event) {
}
/**
* Providing a list of tag records, this function validates each pair and builds a json string
* that can be stored in the quiz_slots.tags field.
* Retrieves tag information for the given quiz slot.
* A quiz slot have some tags if and only if it is representing a random question by tags.
*
* @param stdClass[] $tagrecords List of tag objects with id and name properties.
* @return string
* @param int $slotid The id of the quiz slot.
* @return stdClass[] List of quiz_slot_tags records.
*/
function quiz_build_random_question_tag_json($tagrecords) {
$tags = [];
foreach ($tagrecords as $tagrecord) {
if ($tagrecord->id && $tag = core_tag_tag::get($tagrecord->id, 'id, name')) {
$tags[] = [
'id' => (int)$tagrecord->id,
'name' => $tag->name
];
} else if ($tag = core_tag_tag::get_by_name(0, $tagrecord->name, 'id, name')) {
$tags[] = [
'id' => (int)$tag->id,
'name' => $tagrecord->name
];
function quiz_retrieve_slot_tags($slotid) {
global $DB;
$slottags = $DB->get_records('quiz_slot_tags', ['slotid' => $slotid]);
$tagsbyid = core_tag_tag::get_bulk(array_filter(array_column($slottags, 'tagid')), 'id, name');
$tagcollid = core_tag_area::get_collection('core', 'question');
$tagsbyname = false; // It will be loaded later if required.
foreach ($slottags as $slottag) {
if (isset($tagsbyid[$slottag->tagid])) {
$slottag->tagname = $tagsbyid[$slottag->tagid]->name; // Make sure that we're returning the most updated tag name.
} else {
$tags[] = [
'id' => null,
'name' => $tagrecord->name
];
}
}
return json_encode($tags);
}
/**
* Providing tags data in the JSON format, this function returns tag records containing the id and name properties.
*
* @param string $tagsjson The JSON string representing an array of tags in the [{"id":tagid,"name":"tagname"}] format.
* E.g. [{"id":1,"name":"tag1"},{"id":2,"name":"tag2"}]
* Usually equal to the value of the tags field retrieved from the quiz_slots table.
* @param bool $matchbyid If set to true, then the function tries to find tags by their id.
* If no tag is found by the tag id or if $matchbyid is set to false, then the function tries to find the tag by its name.
* @return array An array of tags containing the id and name properties, indexed by tag ids.
*/
function quiz_extract_random_question_tags($tagsjson, $matchbyid = true) {
$tagrecords = [];
if (!empty($tagsjson)) {
$tags = json_decode($tagsjson);
foreach ($tags as $tagdata) {
if ($matchbyid && $tag = core_tag_tag::get($tagdata->id, 'id, name')) {
$tagrecords[] = $tag->to_object();
} else if ($tag = core_tag_tag::get_by_name(0, $tagdata->name, 'id, name')) {
$tagrecords[] = $tag->to_object();
if ($tagsbyname === false) {
// We were hoping that this query could be avoided, but life showed its other side to us!
$tagsbyname = core_tag_tag::get_by_name_bulk($tagcollid, array_column($slottags, 'tagname'), 'id, name');
}
if (isset($tagsbyname[$slottag->tagname])) {
$slottag->tagid = $tagsbyname[$slottag->tagname]->id; // Make sure that we're returning the current tag id
// that matches the given tag name.
} else {
$tagrecords[] = (object)[
'id' => null,
'name' => $tagdata->name
];
$slottag->tagid = null; // The tag does not exist anymore (neither the tag id nor the tag name
// matches an existing tag).
// We still need to include this row in the result as some callers might
// be interested in these rows. An example is the editing forms that still
// need to display tag names even if they don't exist anymore.
}
}
}
return $tagrecords;
return $slottags;
}
/**
* Providing tags data in the JSON format, this function returns tagids.
* Retrieves tag ids for the given quiz slot.
* A quiz slot have some tags if and only if it is representing a random question by tags.
*
* @param string $tagsjson The JSON string representing an array of tags in the [{"id":tagid,"name":"tagname"}] format.
* E.g. [{"id":1,"name":"tag1"},{"id":2,"name":"tag2"}]
* Usually equal to the value of the tags field retrieved from the {quiz_slots} table.
* @param bool $matchbyid If set to true, then this function relies on the tag ids that are stored in $tagsjson to find tags.
* If no tag is found by the tag id or if $matchbyid is set to false, then this function tries to find the tag by its name.
* @return int[] List of tag ids.
* @param int $slotid The id of the quiz slot.
* @return int[]
*/
function quiz_extract_random_question_tag_ids($tagsjson, $matchbyid = true) {
$tags = quiz_extract_random_question_tags($tagsjson, $matchbyid);
function quiz_retrieve_slot_tag_ids($slotid) {
$tags = quiz_retrieve_slot_tags($slotid);
// Only work with tags that exist.
return array_filter(array_column($tags, 'id'));
return array_filter(array_column($tags, 'tagid'));
}
/**
Binary file not shown.
+413
View File
@@ -0,0 +1,413 @@
<?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 {@link \mod_quiz\local\structure\slot_random} class.
*
* @package mod_quiz
* @category test
* @copyright 2018 Shamim Rezaie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Class mod_quiz_local_structure_slot_random_test
* Class for tests related to the {@link \mod_quiz\local\structure\slot_random} class.
*
* @copyright 2018 Shamim Rezaie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class mod_quiz_local_structure_slot_random_test extends advanced_testcase {
/**
* Constructor test.
*/
public function test_constructor() {
global $SITE;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
// Create a random question without adding it to a quiz.
// We don't want to use quiz_add_random_questions because that itself, instantiates an object from the slot_random class.
$form = new stdClass();
$form->category = $category->id . ',' . $category->contextid;
$form->includesubcategories = true;
$form->fromtags = [];
$form->defaultmark = 1;
$form->hidden = 1;
$form->stamp = make_unique_id_code();
$question = new stdClass();
$question->qtype = 'random';
$question = question_bank::get_qtype('random')->save_question($question, $form);
$randomslotdata = new stdClass();
$randomslotdata->quizid = $quiz->id;
$randomslotdata->questionid = $question->id;
$randomslotdata->questioncategoryid = $category->id;
$randomslotdata->includingsubcategories = 1;
$randomslotdata->maxmark = 1;
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('record');
$rcp->setAccessible(true);
$record = $rcp->getValue($randomslot);
$this->assertEquals($quiz->id, $record->quizid);
$this->assertEquals($question->id, $record->questionid);
$this->assertEquals($category->id, $record->questioncategoryid);
$this->assertEquals(1, $record->includingsubcategories);
$this->assertEquals(1, $record->maxmark);
}
public function test_get_quiz_quiz() {
global $SITE, $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
quiz_add_random_questions($quiz, 0, $category->id, 1, false);
// Get the random question's id. It is at the first slot.
$questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
$randomslotdata = new stdClass();
$randomslotdata->quizid = $quiz->id;
$randomslotdata->questionid = $questionid;
$randomslotdata->questioncategoryid = $category->id;
$randomslotdata->includingsubcategories = 1;
$randomslotdata->maxmark = 1;
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
// The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
unset($quiz->cmid);
$this->assertEquals($quiz, $randomslot->get_quiz());
}
public function test_set_quiz() {
global $SITE, $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
quiz_add_random_questions($quiz, 0, $category->id, 1, false);
// Get the random question's id. It is at the first slot.
$questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
$randomslotdata = new stdClass();
$randomslotdata->quizid = $quiz->id;
$randomslotdata->questionid = $questionid;
$randomslotdata->questioncategoryid = $category->id;
$randomslotdata->includingsubcategories = 1;
$randomslotdata->maxmark = 1;
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
// The create_instance had injected an additional cmid propery to the quiz. Let's remove that.
unset($quiz->cmid);
$randomslot->set_quiz($quiz);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('quiz');
$rcp->setAccessible(true);
$quizpropery = $rcp->getValue($randomslot);
$this->assertEquals($quiz, $quizpropery);
}
private function setup_for_test_tags($tagnames) {
global $SITE, $DB;
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
quiz_add_random_questions($quiz, 0, $category->id, 1, false);
// Get the random question's id. It is at the first slot.
$questionid = $DB->get_field('quiz_slots', 'questionid', array('quizid' => $quiz->id, 'slot' => 1));
$randomslotdata = new stdClass();
$randomslotdata->quizid = $quiz->id;
$randomslotdata->questionid = $questionid;
$randomslotdata->questioncategoryid = $category->id;
$randomslotdata->includingsubcategories = 1;
$randomslotdata->maxmark = 1;
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
// Create tags.
foreach ($tagnames as $tagname) {
$tagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => $tagname,
'description' => $tagname . ' desc'
);
$tags[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
}
return array($randomslot, $tags);
}
public function test_set_tags() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar']);
$randomslot->set_tags([$tags['foo'], $tags['bar']]);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
$this->assertEquals([
$tags['foo']->id => $tags['foo'],
$tags['bar']->id => $tags['bar'],
], $tagspropery);
}
public function test_set_tags_twice() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
// Set tags for the first time.
$randomslot->set_tags([$tags['foo'], $tags['bar']]);
// Now set the tags again.
$randomslot->set_tags([$tags['baz']]);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
$this->assertEquals([
$tags['baz']->id => $tags['baz'],
], $tagspropery);
}
public function test_set_tags_duplicates() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
$randomslot->set_tags([$tags['foo'], $tags['bar'], $tags['foo']]);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
$this->assertEquals([
$tags['foo']->id => $tags['foo'],
$tags['bar']->id => $tags['bar'],
], $tagspropery);
}
public function test_set_tags_by_id() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
$randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
// The set_tags_by_id function only retrieves id and name fields of the tag object.
$this->assertCount(2, $tagspropery);
$this->assertArrayHasKey($tags['foo']->id, $tagspropery);
$this->assertArrayHasKey($tags['bar']->id, $tagspropery);
$this->assertEquals(
(object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
$tagspropery[$tags['foo']->id]->to_object()
);
$this->assertEquals(
(object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
$tagspropery[$tags['bar']->id]->to_object()
);
}
public function test_set_tags_by_id_twice() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
// Set tags for the first time.
$randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id]);
// Now set the tags again.
$randomslot->set_tags_by_id([$tags['baz']->id]);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
// The set_tags_by_id function only retrieves id and name fields of the tag object.
$this->assertCount(1, $tagspropery);
$this->assertArrayHasKey($tags['baz']->id, $tagspropery);
$this->assertEquals(
(object)['id' => $tags['baz']->id, 'name' => $tags['baz']->name],
$tagspropery[$tags['baz']->id]->to_object()
);
}
public function test_set_tags_by_id_duplicates() {
$this->resetAfterTest();
$this->setAdminUser();
list($randomslot, $tags) = $this->setup_for_test_tags(['foo', 'bar', 'baz']);
$randomslot->set_tags_by_id([$tags['foo']->id, $tags['bar']->id], $tags['foo']->id);
$rc = new ReflectionClass('\mod_quiz\local\structure\slot_random');
$rcp = $rc->getProperty('tags');
$rcp->setAccessible(true);
$tagspropery = $rcp->getValue($randomslot);
// The set_tags_by_id function only retrieves id and name fields of the tag object.
$this->assertCount(2, $tagspropery);
$this->assertArrayHasKey($tags['foo']->id, $tagspropery);
$this->assertArrayHasKey($tags['bar']->id, $tagspropery);
$this->assertEquals(
(object)['id' => $tags['foo']->id, 'name' => $tags['foo']->name],
$tagspropery[$tags['foo']->id]->to_object()
);
$this->assertEquals(
(object)['id' => $tags['bar']->id, 'name' => $tags['bar']->name],
$tagspropery[$tags['bar']->id]->to_object()
);
}
public function test_insert() {
global $SITE, $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $questiongenerator->create_question_category();
// Create a random question without adding it to a quiz.
$form = new stdClass();
$form->category = $category->id . ',' . $category->contextid;
$form->includesubcategories = true;
$form->fromtags = [];
$form->defaultmark = 1;
$form->hidden = 1;
$form->stamp = make_unique_id_code();
$question = new stdClass();
$question->qtype = 'random';
$question = question_bank::get_qtype('random')->save_question($question, $form);
// Prepare 2 tags.
$tagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'foo',
'description' => 'foo desc'
);
$footag = $this->getDataGenerator()->create_tag($tagrecord);
$tagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'bar',
'description' => 'bar desc'
);
$bartag = $this->getDataGenerator()->create_tag($tagrecord);
$randomslotdata = new stdClass();
$randomslotdata->quizid = $quiz->id;
$randomslotdata->questionid = $question->id;
$randomslotdata->questioncategoryid = $category->id;
$randomslotdata->includingsubcategories = 1;
$randomslotdata->maxmark = 1;
// Insert the random question to the quiz.
$randomslot = new \mod_quiz\local\structure\slot_random($randomslotdata);
$randomslot->set_tags([$footag, $bartag]);
$randomslot->insert(1); // Put the question on the first page of the quiz.
// Get the random question's quiz_slot. It is at the first slot.
$quizslot = $DB->get_record('quiz_slots', array('quizid' => $quiz->id, 'slot' => 1));
// Get the random question's tags from quiz_slot_tags. It is at the first slot.
$quizslottags = $DB->get_records('quiz_slot_tags', array('slotid' => $quizslot->id));
$this->assertEquals($question->id, $quizslot->questionid);
$this->assertEquals($category->id, $quizslot->questioncategoryid);
$this->assertEquals(1, $quizslot->includingsubcategories);
$this->assertEquals(1, $quizslot->maxmark);
$this->assertCount(2, $quizslottags);
$this->assertEquals(
[
['tagid' => $footag->id, 'tagname' => $footag->name],
['tagid' => $bartag->id, 'tagname' => $bartag->name]
],
array_map(function($slottag) {
return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
}, $quizslottags),
'', 0.0, 10, true);
}
}
+147 -202
View File
@@ -421,223 +421,168 @@ class mod_quiz_locallib_testcase extends advanced_testcase {
$this->assertEquals($comparearray, quiz_get_user_timeclose($course->id));
}
public function test_quiz_build_random_question_tag_json() {
$this->resetAfterTest();
/**
* This function creates a quiz with some standard (non-random) and some random questions.
* The standard questions are created first and then random questions follow them.
* So in a quiz with 3 standard question and 2 random question, the first random question is at slot 4.
*
* @param int $qnum Number of standard questions that should be created in the quiz.
* @param int $randomqnum Number of random questions that should be created in the quiz.
* @param array $questiontags Tags to be used for random questions.
* This is an array in the following format:
* [
* 0 => ['foo', 'bar'],
* 1 => ['baz', 'qux']
* ]
* @param string[] $unusedtags Some additional tags to be created.
* @return array An array of 2 elements: $quiz and $tagobjects.
* $tagobjects is an associative array of all created tag objects with its key being tag names.
*/
private function setup_quiz_and_tags($qnum, $randomqnum, $questiontags = [], $unusedtags = []) {
global $SITE;
// Setup test data.
$footagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'foo',
'description' => 'foo desc'
);
$footag = $this->getDataGenerator()->create_tag($footagrecord);
$bartagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'bar',
'description' => 'bar desc'
);
$bartag = $this->getDataGenerator()->create_tag($bartagrecord);
$baztagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'baz',
'description' => 'baz desc'
);
$baztag = $this->getDataGenerator()->create_tag($baztagrecord);
$quxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'qux',
'description' => 'qux desc'
);
$quxtag = $this->getDataGenerator()->create_tag($quxtagrecord);
$quuxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'quux',
'description' => 'quux desc'
);
$quuxtag = $this->getDataGenerator()->create_tag($quuxtagrecord);
$tagobjects = [];
$tagrecords = array(
(object)[
'id' => $footag->id,
'name' => 'foo'
],
(object)[
'id' => 999, // An invalid tag id.
'name' => 'bar'
],
(object)[
'id' => null,
'name' => 'baz'
],
(object)[
'id' => $quxtag->id,
'name' => 'invalidqux' // An invalid tag name.
],
(object)[
'id' => 999, // An invalid tag id.
'name' => 'invalidquux' // An invalid tag name.
],
);
// Get all the tags that need to be created.
$alltags = [];
foreach ($questiontags as $questiontag) {
$alltags = array_merge($alltags, $questiontag);
}
$alltags = array_merge($alltags, $unusedtags);
$alltags = array_unique($alltags);
$expectedjson = json_encode(array(
['id' => (int)$footag->id, 'name' => $footag->name],
['id' => (int)$bartag->id, 'name' => $bartag->name],
['id' => (int)$baztag->id, 'name' => $baztag->name],
['id' => (int)$quxtag->id, 'name' => $quxtag->name],
['id' => null, 'name' => 'invalidquux'],
));
$this->assertEquals($expectedjson, quiz_build_random_question_tag_json($tagrecords));
// Create tags.
foreach ($alltags as $tagname) {
$tagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => $tagname,
'description' => $tagname . ' desc'
);
$tagobjects[$tagname] = $this->getDataGenerator()->create_tag($tagrecord);
}
// Create a quiz.
$quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
$quiz = $quizgenerator->create_instance(array('course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0));
// Create a question category in the system context.
$questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
$cat = $questiongenerator->create_question_category();
// Setup standard questions.
for ($i = 0; $i < $qnum; $i++) {
$question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
quiz_add_quiz_question($question->id, $quiz);
}
// Setup random questions.
for ($i = 0; $i < $randomqnum; $i++) {
// Just create a standard question first, so there would be enough questions to pick a random question from.
$question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
$tagids = [];
if (!empty($questiontags[$i])) {
foreach ($questiontags[$i] as $tagname) {
$tagids[] = $tagobjects[$tagname]->id;
}
}
quiz_add_random_questions($quiz, 0, $cat->id, 1, false, $tagids);
}
return array($quiz, $tagobjects);
}
public function test_quiz_extract_random_question_tags() {
public function test_quiz_retrieve_slot_tags() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$footagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'foo',
'description' => 'foo desc'
);
$footag = $this->getDataGenerator()->create_tag($footagrecord);
$bartagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'bar',
'description' => 'bar desc'
);
$bartag = $this->getDataGenerator()->create_tag($bartagrecord);
$baztagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'baz',
'description' => 'baz desc'
);
$baztag = $this->getDataGenerator()->create_tag($baztagrecord);
$quxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'qux',
'description' => 'qux desc'
);
$quxtag = $this->getDataGenerator()->create_tag($quxtagrecord);
$quuxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'quux',
'description' => 'quux desc'
);
$quuxtag = $this->getDataGenerator()->create_tag($quuxtagrecord);
list($quiz, $tags) = $this->setup_quiz_and_tags(1, 1, [['foo', 'bar']], ['baz']);
$tagjson = json_encode(array(
[
'id' => $footag->id,
'name' => 'foo'
],
[
'id' => 999, // An invalid tag id.
'name' => 'bar'
],
[
'id' => null,
'name' => 'baz'
],
[
'id' => $quxtag->id,
'name' => 'invalidqux' // An invalid tag name.
],
[
'id' => 999, // An invalid tag id.
'name' => 'invalidquux' // An invalid tag name.
],
));
// Get the random question's slotid. It is at the second slot.
$slotid = $DB->get_field('quiz_slots', 'id', array('quizid' => $quiz->id, 'slot' => 2));
$slottags = quiz_retrieve_slot_tags($slotid);
$expectedrecords = array(
(object)['id' => $footag->id, 'name' => $footag->name],
(object)['id' => $bartag->id, 'name' => $bartag->name],
(object)['id' => $baztag->id, 'name' => $baztag->name],
(object)['id' => $quxtag->id, 'name' => $quxtag->name],
(object)['id' => null, 'name' => 'invalidquux'],
);
$this->assertEquals($expectedrecords, quiz_extract_random_question_tags($tagjson));
$this->assertEquals(
[
['tagid' => $tags['foo']->id, 'tagname' => $tags['foo']->name],
['tagid' => $tags['bar']->id, 'tagname' => $tags['bar']->name]
],
array_map(function($slottag) {
return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
}, $slottags),
'', 0.0, 10, true);
}
public function test_quiz_extract_random_question_tag_ids() {
public function test_quiz_retrieve_slot_tags_with_removed_tag() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
// Setup test data.
$footagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'foo',
'description' => 'foo desc'
);
$footag = $this->getDataGenerator()->create_tag($footagrecord);
$bartagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'bar',
'description' => 'bar desc'
);
$bartag = $this->getDataGenerator()->create_tag($bartagrecord);
$baztagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'baz',
'description' => 'baz desc'
);
$baztag = $this->getDataGenerator()->create_tag($baztagrecord);
$quxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'qux',
'description' => 'qux desc'
);
$quxtag = $this->getDataGenerator()->create_tag($quxtagrecord);
$quuxtagrecord = array(
'isstandard' => 1,
'flag' => 0,
'rawname' => 'quux',
'description' => 'quux desc'
);
$quuxtag = $this->getDataGenerator()->create_tag($quuxtagrecord);
list($quiz, $tags) = $this->setup_quiz_and_tags(1, 1, [['foo', 'bar']], ['baz']);
$tagjson = json_encode(array(
[
'id' => $footag->id,
'name' => 'foo'
],
[
'id' => 999, // An invalid tag id.
'name' => 'bar'
],
[
'id' => null,
'name' => 'baz'
],
[
'id' => $quxtag->id,
'name' => 'invalidqux' // An invalid tag name.
],
[
'id' => 999, // An invalid tag id.
'name' => 'invalidquux' // An invalid tag name.
],
));
// Get the random question's slotid. It is at the second slot.
$slotid = $DB->get_field('quiz_slots', 'id', array('quizid' => $quiz->id, 'slot' => 2));
$slottags = quiz_retrieve_slot_tags($slotid);
$expectedrecords = array(
$footag->id,
$bartag->id,
$baztag->id,
$quxtag->id,
);
// Now remove the foo tag and check again.
core_tag_tag::delete_tags([$tags['foo']->id]);
$slottags = quiz_retrieve_slot_tags($slotid);
$this->assertEquals($expectedrecords, quiz_extract_random_question_tag_ids($tagjson));
$this->assertEquals(
[
['tagid' => null, 'tagname' => $tags['foo']->name],
['tagid' => $tags['bar']->id, 'tagname' => $tags['bar']->name]
],
array_map(function($slottag) {
return ['tagid' => $slottag->tagid, 'tagname' => $slottag->tagname];
}, $slottags),
'', 0.0, 10, true);
}
public function test_quiz_retrieve_slot_tags_for_standard_question() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
list($quiz, $tags) = $this->setup_quiz_and_tags(1, 1, [['foo', 'bar']]);
// Get the standard question's slotid. It is at the first slot.
$slotid = $DB->get_field('quiz_slots', 'id', array('quizid' => $quiz->id, 'slot' => 1));
// There should be no slot tags for a non-random question.
$this->assertCount(0, quiz_retrieve_slot_tags($slotid));
}
public function test_quiz_retrieve_slot_tag_ids() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
list($quiz, $tags) = $this->setup_quiz_and_tags(1, 1, [['foo', 'bar']], ['baz']);
// Get the random question's slotid. It is at the second slot.
$slotid = $DB->get_field('quiz_slots', 'id', array('quizid' => $quiz->id, 'slot' => 2));
$tagids = quiz_retrieve_slot_tag_ids($slotid);
$this->assertEquals([$tags['foo']->id, $tags['bar']->id], $tagids, '', 0.0, 10, true);
}
public function test_quiz_retrieve_slot_tag_ids_for_standard_question() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
list($quiz, $tags) = $this->setup_quiz_and_tags(1, 1, [['foo', 'bar']], ['baz']);
// Get the standard question's slotid. It is at the first slot.
$slotid = $DB->get_field('quiz_slots', 'id', array('quizid' => $quiz->id, 'slot' => 1));
$tagids = quiz_retrieve_slot_tag_ids($slotid);
$this->assertEquals([], $tagids, '', 0.0, 10, true);
}
}
+11 -2
View File
@@ -36,6 +36,7 @@ class mod_quiz_tags_testcase extends advanced_testcase {
global $CFG, $USER, $DB;
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
require_once($CFG->dirroot . '/mod/quiz/locallib.php');
$this->resetAfterTest();
$this->setAdminUser();
@@ -82,8 +83,16 @@ class mod_quiz_tags_testcase extends advanced_testcase {
$tag3 = core_tag_tag::get_by_name(0, 't3', 'id, name');
$this->assertNotFalse($tag3);
$tagrecords = array($tag2->to_object());
$this->assertEquals(quiz_build_random_question_tag_json($tagrecords), $question->randomfromtags);
$slottags = quiz_retrieve_slot_tags($question->slotid);
$this->assertEquals(
[
['tagid' => $tag2->id, 'tagname' => $tag2->name]
],
array_map(function($tag) {
return ['tagid' => $tag->tagid, 'tagname' => $tag->tagname];
}, $slottags),
'', 0.0, 10, true
);
$defaultcategory = question_get_default_category(context_course::instance($newcourseid)->id);
$this->assertEquals($defaultcategory->id, $question->randomfromcategory);
+1 -1
View File
@@ -24,7 +24,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018020701;
$plugin->version = 2018040800;
$plugin->requires = 2017110800;
$plugin->component = 'mod_quiz';
$plugin->cron = 60;
+1 -1
View File
@@ -209,7 +209,7 @@ class core_tag_tag {
}
/**
* Simple function to just return a single tag object by its id
* Simple function to just return an array of tag objects by their ids
*
* @param int[] $ids
* @param string $returnfields which fields do we want returned from table {tag}.