Skip to content

Commit

Permalink
Merge branch 'MDL-63812' of https://github.com/timhunt/moodle
Browse files Browse the repository at this point in the history
  • Loading branch information
abgreeve committed May 25, 2020
2 parents 4404ced + 2bfb8d4 commit d602189
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 92 deletions.
1 change: 0 additions & 1 deletion question/engine/bank.php
Expand Up @@ -264,7 +264,6 @@ public static function load_question_data($questionid) {
* @return question_definition loaded from the database.
*/
public static function load_question($questionid, $allowshuffle = true) {
global $DB;

if (self::$testmode) {
// Evil, test code in production, but no way round it.
Expand Down
27 changes: 26 additions & 1 deletion question/type/ddwtos/tests/helper.php
Expand Up @@ -34,7 +34,7 @@
*/
class qtype_ddwtos_test_helper extends question_test_helper {
public function get_test_questions() {
return array('fox', 'maths', 'oddgroups');
return array('fox', 'maths', 'oddgroups', 'missingchoiceno');
}

/**
Expand Down Expand Up @@ -128,6 +128,31 @@ public function get_ddwtos_question_form_data_oddgroups() {
return $fromform;
}

/**
* Get data required to save a drag-drop into text question where the author
* missed out one of the group numbers.
*
* @return stdClass data to create a ddwtos question.
*/
public function get_ddwtos_question_form_data_missingchoiceno() {
$fromform = new stdClass();

$fromform->name = 'Drag-drop into text question with one index missing';
$fromform->questiontext = ['text' => 'The [[1]] sat on the [[3]].', 'format' => FORMAT_HTML];
$fromform->defaultmark = 1.0;
$fromform->generalfeedback = array('text' => 'The right answer is: "The cat sat on the mat."', 'format' => FORMAT_HTML);
$fromform->choices = array(
array('answer' => 'cat', 'choicegroup' => '1'),
array('answer' => '', 'choicegroup' => '1'),
array('answer' => 'mat', 'choicegroup' => '1'),
);
test_question_maker::set_standard_combined_feedback_form_data($fromform);
$fromform->shownumcorrect = 0;
$fromform->penalty = 0.3333333;

return $fromform;
}

/**
* @return qtype_ddwtos_question
*/
Expand Down
25 changes: 25 additions & 0 deletions question/type/ddwtos/tests/questiontype_test.php
Expand Up @@ -117,6 +117,31 @@ public function test_can_analyse_responses() {
$this->assertTrue($this->qtype->can_analyse_responses());
}

public function test_save_question() {
$this->resetAfterTest();

$syscontext = context_system::instance();
/** @var core_question_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('core_question');
$category = $generator->create_question_category(['contextid' => $syscontext->id]);

$fromform = test_question_maker::get_question_form_data('ddwtos', 'missingchoiceno');
$fromform->category = $category->id . ',' . $syscontext->id;

$question = new stdClass();
$question->category = $category->id;
$question->qtype = 'ddwtos';
$question->createdby = 0;

$this->qtype->save_question($question, $fromform);
$q = question_bank::load_question($question->id);
// We just want to verify that this does not cause errors,
// but also verify some of the outcome.
$this->assertEquals('The [[1]] sat on the [[2]].', $q->questiontext);
$this->assertEquals([1 => 1, 2 => 1], $q->places);
$this->assertEquals([1 => 1, 2 => 2], $q->rightchoices);
}

public function test_initialise_question_instance() {
$qdata = $this->get_test_question_data();

Expand Down
36 changes: 31 additions & 5 deletions question/type/gapselect/questiontypebase.php
Expand Up @@ -49,22 +49,48 @@ protected abstract function choice_options_to_feedback($choice);
public function save_question_options($question) {
global $DB;
$context = $question->context;
$result = new stdClass();

// This question type needs the choices to be consecutively numbered, but
// there is no reason why the question author should have done that,
// so renumber if necessary.
// Insert all the new answers.
$nonblankchoices = [];
$questiontext = $question->questiontext;
$newkey = 0;
foreach ($question->choices as $key => $choice) {
if (trim($choice['answer']) == '') {
continue;
}

$nonblankchoices[] = $choice;
if ($newkey != $key) {
// Safe to do this in this order, because we will always be replacing
// a bigger number with a smaller number that is not present.
// Numbers in the question text always one bigger than the array index.
$questiontext = str_replace('[[' . ($key + 1) . ']]', '[[' . ($newkey + 1) . ']]',
$questiontext);
}
$newkey += 1;
}
$question->choices = $nonblankchoices;
if ($questiontext !== $question->questiontext) {
$DB->set_field('question', 'questiontext', $questiontext,
['id' => $question->id]);
$question->questiontext = $questiontext;
}

$oldanswers = $DB->get_records('question_answers',
array('question' => $question->id), 'id ASC');

// Insert all the new answers.
foreach ($question->choices as $key => $choice) {

if (trim($choice['answer']) == '') {
continue;
}
// Answer guaranteed to be non-blank. See above.

$feedback = $this->choice_options_to_feedback($choice);

if ($answer = array_shift($oldanswers)) {
$answer->answer = $choice['answer'];
$answer->answer = trim($choice['answer']);
$answer->feedback = $feedback;
$DB->update_record('question_answers', $answer);

Expand Down
149 changes: 136 additions & 13 deletions question/type/gapselect/tests/helper.php
Expand Up @@ -32,12 +32,91 @@
* @copyright 2011 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_gapselect_test_helper {
class qtype_gapselect_test_helper extends question_test_helper {

public function get_test_questions() {
return array('fox', 'maths', 'currency', 'multilang', 'missingchoiceno');
}

/**
* Get data you would get by loading a typical select missing words question.
*
* @return stdClass as returned by question_bank::load_question_data for this qtype.
*/
public static function get_gapselect_question_data_fox() {
global $USER;

$gapselect = new stdClass();
$gapselect->id = 0;
$gapselect->category = 0;
$gapselect->contextid = 0;
$gapselect->parent = 0;
$gapselect->questiontextformat = FORMAT_HTML;
$gapselect->generalfeedbackformat = FORMAT_HTML;
$gapselect->defaultmark = 1;
$gapselect->penalty = 0.3333333;
$gapselect->length = 1;
$gapselect->stamp = make_unique_id_code();
$gapselect->version = make_unique_id_code();
$gapselect->hidden = 0;
$gapselect->idnumber = null;
$gapselect->timecreated = time();
$gapselect->timemodified = time();
$gapselect->createdby = $USER->id;
$gapselect->modifiedby = $USER->id;

$gapselect->name = 'Selection from drop down list question';
$gapselect->questiontext = 'The [[1]] brown [[2]] jumped over the [[3]] dog.';
$gapselect->generalfeedback = 'This sentence uses each letter of the alphabet.';
$gapselect->qtype = 'gapselect';

$gapselect->options = new stdClass();
$gapselect->options->shuffleanswers = true;

test_question_maker::set_standard_combined_feedback_fields($gapselect->options);

$gapselect->options->answers = array(
(object) array('answer' => 'quick', 'feedback' => '1'),
(object) array('answer' => 'fox', 'feedback' => '2'),
(object) array('answer' => 'lazy', 'feedback' => '3'),
(object) array('answer' => 'assiduous', 'feedback' => '3'),
(object) array('answer' => 'dog', 'feedback' => '2'),
(object) array('answer' => 'slow', 'feedback' => '1'),
);

return $gapselect;
}

/**
* Get data required to save a select missing words question where
* the author missed out one of the group numbers.
*
* @return stdClass data to create a gapselect question.
*/
public function get_gapselect_question_form_data_missingchoiceno() {
$fromform = new stdClass();

$fromform->name = 'Select missing words question';
$fromform->questiontext = ['text' => 'The [[1]] sat on the [[3]].', 'format' => FORMAT_HTML];
$fromform->defaultmark = 1.0;
$fromform->generalfeedback = ['text' => 'The right answer is: "The cat sat on the mat."', 'format' => FORMAT_HTML];
$fromform->choices = [
['answer' => 'cat', 'choicegroup' => '1'],
['answer' => '', 'choicegroup' => '1'],
['answer' => 'mat', 'choicegroup' => '1'],
];
test_question_maker::set_standard_combined_feedback_form_data($fromform);
$fromform->shownumcorrect = 0;
$fromform->penalty = 0.3333333;

return $fromform;
}

/**
* Get an example gapselect question to use for testing. This examples has one of each item.
* @return qtype_gapselect_question
*/
public static function make_a_gapselect_question() {
public static function make_gapselect_question_fox() {
question_bank::load_question_definition_classes('gapselect');
$gapselect = new qtype_gapselect_question();

Expand Down Expand Up @@ -75,7 +154,7 @@ public static function make_a_gapselect_question() {
* Get an example gapselect question to use for testing. This exmples had unlimited items.
* @return qtype_gapselect_question
*/
public static function make_a_maths_gapselect_question() {
public static function make_gapselect_question_maths() {
question_bank::load_question_definition_classes('gapselect');
$gapselect = new qtype_gapselect_question();

Expand All @@ -93,10 +172,10 @@ public static function make_a_maths_gapselect_question() {

$gapselect->choices = array(
1 => array(
1 => new qtype_gapselect_choice('+', 1, true),
2 => new qtype_gapselect_choice('-', 1, true),
3 => new qtype_gapselect_choice('*', 1, true),
4 => new qtype_gapselect_choice('/', 1, true),
1 => new qtype_gapselect_choice('+', 1),
2 => new qtype_gapselect_choice('-', 1),
3 => new qtype_gapselect_choice('*', 1),
4 => new qtype_gapselect_choice('/', 1),
));

$gapselect->places = array(1 => 1, 2 => 1, 3 => 1, 4 => 1);
Expand All @@ -110,7 +189,7 @@ public static function make_a_maths_gapselect_question() {
* Get an example gapselect question with multilang entries to use for testing.
* @return qtype_gapselect_question
*/
public static function make_a_multilang_gapselect_question() {
public static function make_gapselect_question_multilang() {
question_bank::load_question_definition_classes('gapselect');
$gapselect = new qtype_gapselect_question();

Expand All @@ -129,14 +208,14 @@ public static function make_a_multilang_gapselect_question() {
$gapselect->choices = array(
1 => array(
1 => new qtype_gapselect_choice('<span lang="en" class="multilang">cat</span><span lang="ru" ' .
'class="multilang">кошка</span>', 1, true),
'class="multilang">кошка</span>', 1),
2 => new qtype_gapselect_choice('<span lang="en" class="multilang">dog</span><span lang="ru" ' .
'class="multilang">пес</span>', 1, true)),
'class="multilang">пес</span>', 1)),
2 => array(
1 => new qtype_gapselect_choice('<span lang="en" class="multilang">mat</span><span lang="ru" ' .
'class="multilang">коврике</span>', 2, true),
'class="multilang">коврике</span>', 2),
2 => new qtype_gapselect_choice('<span lang="en" class="multilang">bat</span><span lang="ru" ' .
'class="multilang">бита</span>', 2, true))
'class="multilang">бита</span>', 2))
);

$gapselect->places = array(1 => 1, 2 => 2);
Expand All @@ -151,7 +230,7 @@ public static function make_a_multilang_gapselect_question() {
* This examples includes choices with currency like options.
* @return qtype_gapselect_question
*/
public static function make_a_currency_gapselect_question() {
public static function make_gapselect_question_currency() {
question_bank::load_question_definition_classes('gapselect');
$gapselect = new qtype_gapselect_question();

Expand Down Expand Up @@ -181,4 +260,48 @@ public static function make_a_currency_gapselect_question() {

return $gapselect;
}

/**
* Just for backwards compatibility.
*
* @return qtype_gapselect_question
*/
public static function make_a_gapselect_question() {
debugging('qtype_gapselect_test_helper::make_a_gapselect_question is deprecated. ' .
"Please use test_question_maker::make_question('gapselect') instead.");
return self::make_gapselect_question_fox();
}

/**
* Just for backwards compatibility.
*
* @return qtype_gapselect_question
*/
public static function make_a_maths_gapselect_question() {
debugging('qtype_gapselect_test_helper::make_a_maths_gapselect_question is deprecated. ' .
"Please use test_question_maker::make_question('gapselect', 'maths') instead.");
return self::make_gapselect_question_maths();
}

/**
* Just for backwards compatibility.
*
* @return qtype_gapselect_question
*/
public static function make_a_currency_gapselect_question() {
debugging('qtype_gapselect_test_helper::make_a_currency_gapselect_question is deprecated. ' .
"Please use test_question_maker::make_question('gapselect', 'currency') instead.");
return self::make_gapselect_question_currency();
}

/**
* Just for backwards compatibility.
*
* @return qtype_gapselect_question
*/
public static function make_a_multilang_gapselect_question() {
debugging('qtype_gapselect_test_helper::make_a_multilang_gapselect_question is deprecated. ' .
"Please use test_question_maker::make_question('gapselect', 'multilang') instead.");
return self::make_gapselect_question_multilang();
}
}

0 comments on commit d602189

Please sign in to comment.