diff --git a/question/type/multianswer/lang/en/qtype_multianswer.php b/question/type/multianswer/lang/en/qtype_multianswer.php index e6e1ce1ecdf52..cc6009d4419ff 100644 --- a/question/type/multianswer/lang/en/qtype_multianswer.php +++ b/question/type/multianswer/lang/en/qtype_multianswer.php @@ -67,6 +67,7 @@ $string['questiontypechanged'] = 'Question type changed'; $string['questiontypechangedcomment'] = 'At least one question type has been changed.
Did you add, delete or move a question?
Look ahead.'; $string['questionusedinquiz'] = 'This question is used in {$a->nb_of_quiz} quiz(s), total attempt(s) : {$a->nb_of_attempts} '; +$string['regradeissuenumsubquestionschanged'] = 'The number embedded sub-questions in the question has changed.'; $string['storedqtype'] = 'Stored question type {$a}'; $string['subqresponse'] = 'part {$a->i}: {$a->response}'; $string['unknownquestiontypeofsubquestion'] = 'Unknown question type: {$a->type} of question part # {$a->sub}'; diff --git a/question/type/multianswer/question.php b/question/type/multianswer/question.php index 2910fca66d9ab..62036c263a47b 100644 --- a/question/type/multianswer/question.php +++ b/question/type/multianswer/question.php @@ -78,6 +78,43 @@ public function apply_attempt_state(question_attempt_step $step) { } } + 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->subquestions) != count($otherversion->subquestions)) { + return get_string('regradeissuenumsubquestionschanged', 'qtype_multianswer'); + } + + foreach ($this->subquestions as $i => $subq) { + $subqmessage = $subq->validate_can_regrade_with_other_version($otherversion->subquestions[$i]); + if ($subqmessage) { + return $subqmessage; + } + } + + return null; + } + + public function update_attempt_state_data_for_new_version( + question_attempt_step $oldstep, question_definition $oldquestion) { + parent::update_attempt_state_data_for_new_version($oldstep, $oldquestion); + + $result = []; + foreach ($this->subquestions as $i => $subq) { + $substep = $this->get_substep($oldstep, $i); + $statedata = $subq->update_attempt_state_data_for_new_version( + $substep, $oldquestion->subquestions[$i]); + foreach ($statedata as $name => $value) { + $result[$substep->add_prefix($name)] = $value; + } + } + + return $result; + } + public function get_question_summary() { $summary = $this->html_to_text($this->questiontext, $this->questiontextformat); foreach ($this->subquestions as $i => $subq) { diff --git a/question/type/multianswer/tests/question_test.php b/question/type/multianswer/tests/question_test.php index 0744ee128ea62..ae38468730a7a 100644 --- a/question/type/multianswer/tests/question_test.php +++ b/question/type/multianswer/tests/question_test.php @@ -32,6 +32,7 @@ * @package qtype_multianswer * @copyright 2011 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \qtype_multianswer_question */ class question_test extends \advanced_testcase { public function test_get_expected_data() { @@ -252,4 +253,100 @@ public function test_get_question_definition_for_external_rendering() { $options = $question->get_question_definition_for_external_rendering($qa, $displayoptions); $this->assertNull($options); } + + /** + * Helper method to make a simulated second version of the standard multianswer test question. + * + * The key think is that all the answer ids are changed (increased by 20). + * + * @param \qtype_multianswer_question $question + * @return \qtype_multianswer_question + */ + protected function make_second_version( + \qtype_multianswer_question $question): \qtype_multianswer_question { + $newquestion = fullclone($question); + + $newquestion->subquestions[1]->answers = [ + 36 => new \question_answer(16, 'Apple', 0.3333333, + 'Good', FORMAT_HTML), + 37 => new \question_answer(17, 'Burger', -0.5, + '', FORMAT_HTML), + 38 => new \question_answer(18, 'Hot dog', -0.5, + 'Not a fruit', FORMAT_HTML), + 39 => new \question_answer(19, 'Pizza', -0.5, + '', FORMAT_HTML), + 40 => new \question_answer(20, 'Orange', 0.3333333, + 'Correct', FORMAT_HTML), + 41 => new \question_answer(21, 'Banana', 0.3333333, + '', FORMAT_HTML), + ]; + + $newquestion->subquestions[2]->answers = [ + 42 => new \question_answer(22, 'Raddish', 0.5, + 'Good', FORMAT_HTML), + 43 => new \question_answer(23, 'Chocolate', -0.5, + '', FORMAT_HTML), + 44 => new \question_answer(24, 'Biscuit', -0.5, + 'Not a vegetable', FORMAT_HTML), + 45 => new \question_answer(25, 'Cheese', -0.5, + '', FORMAT_HTML), + 46 => new \question_answer(26, 'Carrot', 0.5, + 'Correct', FORMAT_HTML), + ]; + + return $newquestion; + } + + public function test_validate_can_regrade_with_other_version_ok() { + /** @var \qtype_multianswer_question $question */ + $question = \test_question_maker::make_question('multianswer', 'multiple'); + + $newquestion = $this->make_second_version($question); + + $this->assertNull($newquestion->validate_can_regrade_with_other_version($question)); + } + + public function test_validate_can_regrade_with_other_version_wrong_subquestions() { + /** @var \qtype_multianswer_question $question */ + $question = \test_question_maker::make_question('multianswer', 'multiple'); + + $newquestion = $this->make_second_version($question); + unset($newquestion->subquestions[2]); + + $this->assertEquals( + get_string('regradeissuenumsubquestionschanged', 'qtype_multianswer'), + $newquestion->validate_can_regrade_with_other_version($question)); + } + + public function test_validate_can_regrade_with_other_version_one_wrong_subquestion() { + /** @var \qtype_multianswer_question $question */ + $question = \test_question_maker::make_question('multianswer', 'multiple'); + + $newquestion = $this->make_second_version($question); + unset($newquestion->subquestions[1]->answers[41]); + + $this->assertEquals( + get_string('regradeissuenumchoiceschanged', 'qtype_multichoice'), + $newquestion->validate_can_regrade_with_other_version($question)); + } + + public function test_update_attempt_state_date_from_old_version_ok() { + /** @var \qtype_multianswer_question $question */ + $question = \test_question_maker::make_question('multianswer', 'multiple'); + + $newquestion = $this->make_second_version($question); + + $oldstep = new question_attempt_step(); + $oldstep->set_qt_var('_sub1_order', '16,17,18,19,20,21'); + $oldstep->set_qt_var('_sub2_order', '22,23,24,25,26'); + + $expected = [ + '_sub1_order' => '36,37,38,39,40,41', + '_sub2_order' => '42,43,44,45,46', + ]; + + $this->assertEquals($expected, + $newquestion->update_attempt_state_data_for_new_version($oldstep, $question)); + } + }