MDL-83541 qtypes: Define excluded hash fields and test hints

This commit is contained in:
Mark Johnson
2025-03-14 10:31:26 +07:00
committed by Huong Nguyen
parent 85d85a6a25
commit 2de34d5c0e
20 changed files with 327 additions and 8 deletions
@@ -113,4 +113,46 @@ class restore_qtype_calculated_plugin extends restore_qtype_plugin {
$newitemid = $DB->insert_record('question_calculated_options', $data);
}
}
#[\Override]
public static function convert_backup_to_questiondata(array $backupdata): \stdClass {
$questiondata = parent::convert_backup_to_questiondata($backupdata);
$qtype = $questiondata->qtype;
foreach ($backupdata["plugin_qtype_{$qtype}_question"]['calculated_records']['calculated_record'] as $record) {
foreach ($questiondata->options->answers as &$answer) {
if ($answer->id == $record['answer']) {
$answer->tolerance = $record['tolerance'];
$answer->tolerancetype = $record['tolerancetype'];
$answer->correctanswerlength = $record['correctanswerlength'];
$answer->correctanswerformat = $record['correctanswerformat'];
continue 2;
}
}
}
if (isset($backupdata["plugin_qtype_{$qtype}_question"]['calculated_options'])) {
$questiondata->options = (object) array_merge(
(array) $questiondata->options,
$backupdata["plugin_qtype_{$qtype}_question"]['calculated_options']['calculated_option'][0],
);
}
return $questiondata;
}
#[\Override]
protected function define_excluded_identity_hash_fields(): array {
return [
// These option fields are present in the database, but are only used by calculatedmulti.
'/options/synchronize',
'/options/single',
'/options/shuffleanswers',
'/options/correctfeedback',
'/options/correctfeedbackformat',
'/options/partiallycorrectfeedback',
'/options/partiallycorrectfeedbackformat',
'/options/incorrectfeedback',
'/options/incorrectfeedbackformat',
'/options/answernumbering',
'/options/shownumcorrect',
];
}
}
+15 -1
View File
@@ -133,7 +133,7 @@ class qtype_calculated_test_helper extends question_test_helper {
$fromform->defaultmark = 1.0;
$fromform->generalfeedback = 'Generalfeedback: {={a} + {b}} is the right answer.';
$fromform->unitrole = '3';
$fromform->unitrole = '0';
$fromform->unitpenalty = 0.1;
$fromform->unitgradingtypes = '1';
$fromform->unitsleft = '0';
@@ -187,6 +187,20 @@ class qtype_calculated_test_helper extends question_test_helper {
$fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$fromform->hint = [
[
'text' => 'Add',
'format' => FORMAT_HTML,
],
];
$fromform->unit = [
'x',
];
$fromform->multiplier = [
'1.0',
];
return $fromform;
}
@@ -104,12 +104,18 @@ final class question_type_test extends \advanced_testcase {
$this->assertEquals($question->createdby, $questiondata->modifiedby);
$this->assertEquals('', $questiondata->idnumber);
$this->assertEquals($syscontext->id, $questiondata->contextid);
$this->assertEquals([], $questiondata->hints);
$this->assertCount(1, $questiondata->hints);
$hint = array_pop($questiondata->hints);
$this->assertEquals('Add', $hint->hint);
$this->assertEquals(FORMAT_HTML, $hint->hintformat);
// Options.
$this->assertEquals($questiondata->id, $questiondata->options->question);
$this->assertEquals([], $questiondata->options->units);
$this->assertEquals(qtype_numerical::UNITNONE, $questiondata->options->showunits);
$this->assertCount(1, $questiondata->options->units);
$unit = array_pop($questiondata->options->units);
$this->assertEquals($unit->unit, 'x');
$this->assertEquals($unit->multiplier, '1.0');
$this->assertEquals(qtype_numerical::UNITOPTIONAL, $questiondata->options->showunits);
$this->assertEquals(0, $questiondata->options->unitgradingtype); // Unit role is none, so this is 0.
$this->assertEquals($fromform->unitpenalty, $questiondata->options->unitpenalty);
$this->assertEquals($fromform->unitsleft, $questiondata->options->unitsleft);
@@ -69,4 +69,9 @@ class restore_qtype_calculatedmulti_plugin extends restore_qtype_calculated_plug
}
return $result ? $result : $answer;
}
#[\Override]
protected function define_excluded_identity_hash_fields(): array {
return [];
}
}
@@ -127,4 +127,95 @@ class qtype_calculatedmulti_test_helper extends question_test_helper {
return $q;
}
/**
* Return the form data for a question with a single response.
*
* @return stdClass
*/
public function get_calculatedmulti_question_form_data_singleresponse(): stdClass {
question_bank::load_question_definition_classes('calculated');
$fromform = new stdClass();
$fromform->name = 'Simple sum';
$fromform->questiontext['text'] = 'What is {a} + {b}?';
$fromform->questiontext['format'] = FORMAT_HTML;
$fromform->defaultmark = 1.0;
$fromform->generalfeedback['text'] = 'Generalfeedback: {={a} + {b}} is the right answer.';
$fromform->generalfeedback['format'] = FORMAT_HTML;
$fromform->unitrole = '3';
$fromform->unitpenalty = 0.1;
$fromform->unitgradingtypes = '1';
$fromform->unitsleft = '0';
$fromform->nounits = 1;
$fromform->multiplier = [];
$fromform->multiplier[0] = '1.0';
$fromform->synchronize = 0;
$fromform->answernumbering = 0;
$fromform->shuffleanswers = 0;
$fromform->single = 1;
$fromform->correctfeedback['text'] = 'Very good';
$fromform->correctfeedback['format'] = FORMAT_HTML;
$fromform->partiallycorrectfeedback['text'] = 'Mostly good';
$fromform->partiallycorrectfeedback['format'] = FORMAT_HTML;
$fromform->incorrectfeedback['text'] = 'Completely Wrong';
$fromform->incorrectfeedback['format'] = FORMAT_HTML;
$fromform->shownumcorrect = 1;
$fromform->noanswers = 6;
$fromform->answer = [];
$fromform->answer[0]['text'] = '{a} + {b}';
$fromform->answer[0]['format'] = FORMAT_HTML;
$fromform->answer[1]['text'] = '{a} - {b}';
$fromform->answer[1]['format'] = FORMAT_HTML;
$fromform->answer[2]['text'] = '*';
$fromform->answer[2]['format'] = FORMAT_HTML;
$fromform->fraction = [];
$fromform->fraction[0] = '1.0';
$fromform->fraction[1] = '0.0';
$fromform->fraction[2] = '0.0';
$fromform->tolerance = [];
$fromform->tolerance[0] = 0.001;
$fromform->tolerance[1] = 0.001;
$fromform->tolerance[2] = 0;
$fromform->tolerancetype[0] = 1;
$fromform->tolerancetype[1] = 1;
$fromform->tolerancetype[2] = 1;
$fromform->correctanswerlength[0] = 2;
$fromform->correctanswerlength[1] = 2;
$fromform->correctanswerlength[2] = 2;
$fromform->correctanswerformat[0] = 1;
$fromform->correctanswerformat[1] = 1;
$fromform->correctanswerformat[2] = 1;
$fromform->feedback = [];
$fromform->feedback[0] = [];
$fromform->feedback[0]['format'] = FORMAT_HTML;
$fromform->feedback[0]['text'] = 'Very good.';
$fromform->feedback[1] = [];
$fromform->feedback[1]['format'] = FORMAT_HTML;
$fromform->feedback[1]['text'] = 'Add. not subtract!';
$fromform->feedback[2] = [];
$fromform->feedback[2]['format'] = FORMAT_HTML;
$fromform->feedback[2]['text'] = 'Completely wrong.';
$fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$fromform->hint = [
[
'text' => 'Add',
'format' => FORMAT_HTML,
],
];
return $fromform;
}
}
@@ -205,6 +205,13 @@ class qtype_calculatedsimple_test_helper extends question_test_helper {
$form->definition[19] = '1-0-b';
$form->definition[20] = '1-0-a';
$form->hint = [
[
'text' => 'Add',
'format' => FORMAT_HTML,
],
];
$form->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
return $form;
@@ -88,7 +88,7 @@ final class question_type_test extends \advanced_testcase {
$actualquestiondata = end($actualquestionsdata);
foreach ($questiondata as $property => $value) {
if (!in_array($property, array('id', 'timemodified', 'timecreated', 'options', 'idnumber'))) {
if (!in_array($property, ['id', 'timemodified', 'timecreated', 'options', 'idnumber', 'hints'])) {
$this->assertEquals($value, $actualquestiondata->$property);
}
}
@@ -108,6 +108,11 @@ final class question_type_test extends \advanced_testcase {
}
}
$this->assertCount(1, $actualquestiondata->hints);
$hint = array_pop($actualquestiondata->hints);
$this->assertEquals($formdata->hint[0]['text'], $hint->hint);
$this->assertEquals($formdata->hint[0]['format'], $hint->hintformat);
$datasetloader = new qtype_calculated_dataset_loader($actualquestiondata->id);
$this->assertEquals(10, $datasetloader->get_number_of_items());
@@ -166,4 +166,29 @@ class restore_qtype_ddimageortext_plugin extends restore_qtype_plugin {
return $contents;
}
#[\Override]
public static function convert_backup_to_questiondata(array $backupdata): \stdClass {
$questiondata = parent::convert_backup_to_questiondata($backupdata);
$questiondata->options->drags = array_map(
fn($drag) => (object) $drag,
$backupdata['plugin_qtype_ddimageortext_question']['drags']['drag'] ?? [],
);
$questiondata->options->drops = array_map(
fn($drop) => (object) $drop,
$backupdata['plugin_qtype_ddimageortext_question']['drops']['drop'] ?? [],
);
return $questiondata;
}
#[\Override]
protected function define_excluded_identity_hash_fields(): array {
return [
'/options/drags/id',
'/options/drags/questionid',
'/options/drops/id',
'/options/drops/questionid',
];
}
}
@@ -168,4 +168,28 @@ class restore_qtype_ddmarker_plugin extends restore_qtype_plugin {
return $contents;
}
#[\Override]
public static function convert_backup_to_questiondata(array $backupdata): \stdClass {
$questiondata = parent::convert_backup_to_questiondata($backupdata);
$questiondata->options->drags = array_map(
fn($drag) => (object) $drag,
$backupdata['plugin_qtype_ddmarker_question']['drags']['drag'] ?? [],
);
$questiondata->options->drops = array_map(
fn($drop) => (object) $drop,
$backupdata['plugin_qtype_ddmarker_question']['drops']['drop'] ?? [],
);
return $questiondata;
}
#[\Override]
protected function define_excluded_identity_hash_fields(): array {
return [
'/options/drags/id',
'/options/drags/questionid',
'/options/drops/id',
'/options/drops/questionid',
];
}
}
+7
View File
@@ -99,6 +99,13 @@ class qtype_ddwtos_test_helper extends question_test_helper {
$fromform->penalty = 0.3333333;
$fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$fromform->hint = [
[
'text' => 'Fast',
'format' => FORMAT_HTML,
],
];
return $fromform;
}
+7
View File
@@ -112,6 +112,13 @@ class qtype_gapselect_test_helper extends question_test_helper {
$fromform->penalty = 0.3333333;
$fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$fromform->hint = [
[
'text' => 'Cat',
'format' => FORMAT_HTML,
],
];
return $fromform;
}
@@ -246,4 +246,23 @@ class restore_qtype_match_plugin extends restore_qtype_plugin {
return $contents;
}
#[\Override]
public static function convert_backup_to_questiondata(array $backupdata): \stdClass {
$questiondata = parent::convert_backup_to_questiondata($backupdata);
$questiondata->options = (object) $backupdata["plugin_qtype_match_question"]['matchoptions'][0];
$questiondata->options->subquestions = array_map(
fn($match) => (object) $match,
$backupdata["plugin_qtype_match_question"]['matches']['match'] ?? [],
);
return $questiondata;
}
#[\Override]
protected function define_excluded_identity_hash_fields(): array {
return [
'/options/subquestions/id',
'/options/subquestions/questionid',
];
}
}
+7
View File
@@ -131,6 +131,13 @@ class qtype_match_test_helper extends question_test_helper {
$q->noanswers = 4;
$q->hint = [
[
'text' => 'Frog and newt are the same',
'format' => FORMAT_HTML,
],
];
return $q;
}
@@ -188,7 +188,7 @@ final class question_type_test extends \advanced_testcase {
foreach ($questiondata as $property => $value) {
if (!in_array($property, ['id', 'timemodified', 'timecreated', 'options', 'stamp',
'versionid', 'questionbankentryid'])) {
'versionid', 'questionbankentryid', 'hints'])) {
if (!empty($actualquestiondata)) {
$this->assertEquals($value, $actualquestiondata->$property);
}
@@ -201,6 +201,11 @@ final class question_type_test extends \advanced_testcase {
}
}
$this->assertCount(1, $actualquestiondata->hints);
$hint = array_pop($actualquestiondata->hints);
$this->assertEquals($formdata->hint[0]['text'], $hint->hint);
$this->assertEquals($formdata->hint[0]['format'], $hint->hintformat);
$this->assertObjectHasProperty('subquestions', $actualquestiondata->options);
$subqpropstoignore = array('id');
@@ -199,4 +199,19 @@ class restore_qtype_multianswer_plugin extends restore_qtype_plugin {
return implode(',', $resultarr);
}
#[\Override]
public function define_excluded_identity_hash_fields(): array {
return [
'/options/sequence',
'/options/question',
];
}
#[\Override]
public static function remove_excluded_question_data(stdClass $questiondata, array $excludefields = []): stdClass {
if (isset($questiondata->options->questions)) {
unset($questiondata->options->questions);
}
return parent::remove_excluded_question_data($questiondata, $excludefields);
}
}
@@ -80,4 +80,18 @@ class restore_qtype_numerical_plugin extends restore_qtype_plugin {
$newitemid = $DB->insert_record('question_numerical', $data);
}
}
#[\Override]
public static function convert_backup_to_questiondata(array $backupdata): \stdClass {
$questiondata = parent::convert_backup_to_questiondata($backupdata);
foreach ($backupdata['plugin_qtype_numerical_question']['numerical_records']['numerical_record'] as $record) {
foreach ($questiondata->options->answers as &$answer) {
if ($answer->id == $record['answer']) {
$answer->tolerance = $record['tolerance'];
continue 2;
}
}
}
return $questiondata;
}
}
+7
View File
@@ -164,6 +164,13 @@ class qtype_numerical_test_helper extends question_test_helper {
$form->qtype = 'numerical';
$form->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$form->hint = [
[
'text' => 'Just over 3',
'format' => FORMAT_HTML,
],
];
return $form;
}
+6 -1
View File
@@ -110,7 +110,12 @@ class qtype_shortanswer_test_helper extends question_test_helper {
array('text' => 'That is a bad answer.', 'format' => FORMAT_HTML),
);
$form->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
$form->hint = [
[
'text' => 'Rhymes with dog',
'format' => FORMAT_HTML,
],
];
return $form;
}
@@ -118,7 +118,7 @@ final class question_type_test extends \advanced_testcase {
$actualquestiondata = end($actualquestionsdata);
foreach ($questiondata as $property => $value) {
if (!in_array($property, array('id', 'timemodified', 'timecreated', 'options'))) {
if (!in_array($property, ['id', 'timemodified', 'timecreated', 'options', 'hints'])) {
$this->assertEquals($value, $actualquestiondata->$property);
}
}
@@ -138,6 +138,11 @@ final class question_type_test extends \advanced_testcase {
}
}
}
$this->assertCount(1, $actualquestiondata->hints);
$hint = array_pop($actualquestiondata->hints);
$this->assertEquals($formdata->hint[0]['text'], $hint->hint);
$this->assertEquals($formdata->hint[0]['format'], $hint->hintformat);
}
public function test_question_saving_trims_answers(): void {
@@ -93,4 +93,13 @@ class restore_qtype_truefalse_plugin extends restore_qtype_plugin {
}
return $result;
}
#[\Override]
public function define_excluded_identity_hash_fields(): array {
return [
'/options/trueanswer',
'/options/falseanswer',
'/options/question',
];
}
}