From 1dea18ddf4a207f21eb8de5260b306737c197f44 Mon Sep 17 00:00:00 2001 From: ardelean-emanuel Date: Thu, 26 Sep 2024 23:18:55 +0200 Subject: [PATCH] MDL-76676 qtype_randomsamatch: Fix regrade error --- .../lang/en/qtype_randomsamatch.php | 3 + question/type/randomsamatch/question.php | 39 +++++++++++++ .../randomsamatch/tests/question_test.php | 57 +++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/question/type/randomsamatch/lang/en/qtype_randomsamatch.php b/question/type/randomsamatch/lang/en/qtype_randomsamatch.php index ea5503592d699..849b27dce6428 100644 --- a/question/type/randomsamatch/lang/en/qtype_randomsamatch.php +++ b/question/type/randomsamatch/lang/en/qtype_randomsamatch.php @@ -36,5 +36,8 @@ $string['randomsamatchnumber'] = 'Number of questions to select'; $string['randomsamatch'] = 'Random short-answer matching'; $string['randomsamatchintro'] = 'For each of the following questions, select the matching answer from the menu.'; +$string['regradeissuenumchoiceschanged'] = 'The number of choices has changed.'; +$string['regradeissuenumstemschanged'] = 'The number of sub-questions has changed.'; $string['subcats'] = 'Include subcategories'; $string['subcats_help'] = 'If checked, questions will be choosen from subcategories too.'; + diff --git a/question/type/randomsamatch/question.php b/question/type/randomsamatch/question.php index 587b88e6d932d..c6293e6326cb0 100644 --- a/question/type/randomsamatch/question.php +++ b/question/type/randomsamatch/question.php @@ -92,6 +92,45 @@ public function find_right_answer($wrappedquestion) { } + /** + * Validate if this question can be regraded to a new version. + * @param question_definition $otherversion The new version of the question. + * @return string|null Error message if regrade is not possible, or null if it is. + */ + public function validate_can_regrade_with_other_version(question_definition $otherversion): ?string { + $basemessage = parent::validate_can_regrade_with_other_version($otherversion); + if ($basemessage) { + return $basemessage; + } + if (count($this->stems) != count($otherversion->stems)) { + return get_string('regradeissuenumstemschanged', 'qtype_randomsamatch'); + } + if (count($this->choices) != count($otherversion->choices)) { + return get_string('regradeissuenumchoiceschanged', 'qtype_randomsamatch'); + } + return null; + } + + /** + * Update the attempt state data for a new version of the question. + * @param question_attempt_step $oldstep The old step containing the attempt data. + * @param question_definition $otherversion The new version of the question. + * @return array The updated start data. + */ + public function update_attempt_state_data_for_new_version( + question_attempt_step $oldstep, question_definition $otherversion) { + $saquestions = explode(',', $oldstep->get_qt_var('_stemorder')); + foreach ($saquestions as $questionid) { + $this->stems[$questionid] = $oldstep->get_qt_var('_stem_' . $questionid); + $this->stemformat[$questionid] = $oldstep->get_qt_var('_stemformat_' . $questionid); + $key = $oldstep->get_qt_var('_right_' . $questionid); + $this->right[$questionid] = $key; + $this->choices[$key] = $oldstep->get_qt_var('_choice_' . $key); + } + $startdata = parent::update_attempt_state_data_for_new_version($oldstep, $otherversion); + return $startdata; + } + public function apply_attempt_state(question_attempt_step $step) { $saquestions = explode(',', $step->get_qt_var('_stemorder')); foreach ($saquestions as $questionid) { diff --git a/question/type/randomsamatch/tests/question_test.php b/question/type/randomsamatch/tests/question_test.php index 7baf119df646a..58aee2fc1aadb 100644 --- a/question/type/randomsamatch/tests/question_test.php +++ b/question/type/randomsamatch/tests/question_test.php @@ -31,6 +31,7 @@ * @package qtype_randomsamatch * @copyright 2013 Jean-Michel Vedrine * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \qtype_randomsamatch\question */ class question_test extends \advanced_testcase { @@ -146,5 +147,61 @@ public function test_summarise_response(): void { $this->assertMatchesRegularExpression('/Dog -> \w+; Frog -> \w+/', $summary); } + public function test_validate_can_regrade_with_other_version_ok(): void { + $question = \test_question_maker::make_question('randomsamatch'); + $newquestion = clone($question); + $result = $newquestion->validate_can_regrade_with_other_version($question); + $this->assertNull($result, 'Regrade should be possible when stems and choices have not changed.'); + } + + public function test_validate_can_regrade_with_other_version_bad_stems(): void { + $question = \test_question_maker::make_question('randomsamatch'); + // Ensure stems are populated for the test. + $question->stems = [1 => 'Stem 1', 2 => 'Stem 2']; + $this->assertGreaterThan(1, count($question->stems), 'The stems array should contain more than one element.'); + $newquestion = clone($question); + unset($newquestion->stems[array_key_first($newquestion->stems)]); + $this->assertCount(count($question->stems) - 1, $newquestion->stems, 'The number of stems should be reduced by 1.'); + $result = $newquestion->validate_can_regrade_with_other_version($question); + $this->assertEquals(get_string('regradeissuenumstemschanged', 'qtype_randomsamatch'), $result); + } + + public function test_validate_can_regrade_with_other_version_bad_choices(): void { + $question = \test_question_maker::make_question('randomsamatch'); + // Ensure choices are populated for the test. + $question->choices = [1 => 'Choice 1', 2 => 'Choice 2']; + $this->assertGreaterThan(1, count($question->choices), 'The choices array should contain more than one element.'); + $newquestion = clone($question); + unset($newquestion->choices[array_key_first($newquestion->choices)]); + $this->assertCount(count($question->choices) - 1, $newquestion->choices, 'The number of choices should be reduced by 1.'); + $result = $newquestion->validate_can_regrade_with_other_version($question); + $this->assertEquals(get_string('regradeissuenumchoiceschanged', 'qtype_randomsamatch'), $result); + } + + public function test_update_attempt_state_data_for_new_version_ok(): void { + $question = \test_question_maker::make_question('randomsamatch'); + $question->stems = [1 => 'Stem 1', 2 => 'Stem 2', 3 => 'Stem 3']; + $question->choices = [1 => 'Choice 1', 2 => 'Choice 2', 3 => 'Choice 3']; + $question->right = [1 => 1, 2 => 2, 3 => 3]; + $newquestion = clone($question); + $oldstep = new \question_attempt_step(); + $oldstep->set_qt_var('_stemorder', implode(',', array_keys($question->stems))); + foreach ($question->stems as $key => $value) { + $oldstep->set_qt_var('_stem_' . $key, $value); + $oldstep->set_qt_var('_stemformat_' . $key, FORMAT_HTML); + $oldstep->set_qt_var('_right_' . $key, $question->right[$key]); + $oldstep->set_qt_var('_choice_' . $question->right[$key], $question->choices[$question->right[$key]]); + } + $oldstep->set_qt_var('_choiceorder', implode(',', array_keys($question->choices))); + $startdata = $newquestion->update_attempt_state_data_for_new_version($oldstep, $question); + $this->assertEquals($oldstep->get_qt_var('_stemorder'), $startdata['_stemorder']); + $this->assertEquals($oldstep->get_qt_var('_choiceorder'), $startdata['_choiceorder']); + foreach ($question->stems as $key => $value) { + $this->assertEquals($value, $startdata['_stem_' . $key]); + $this->assertEquals(FORMAT_HTML, $startdata['_stemformat_' . $key]); + $this->assertEquals($question->right[$key], $startdata['_right_' . $key]); + $this->assertEquals($question->choices[$question->right[$key]], $startdata['_choice_' . $question->right[$key]]); + } + } }