diff --git a/tests/backup_restore_test.php b/tests/backup_restore_test.php index 8b895e5d..38d566fd 100644 --- a/tests/backup_restore_test.php +++ b/tests/backup_restore_test.php @@ -36,7 +36,6 @@ use context_course; use core_question_generator; use qtype_formulas; -use qtype_formulas_question; use restore_controller; use test_question_maker; @@ -66,15 +65,6 @@ final class backup_restore_test extends \advanced_testcase { use \quiz_question_helper_test_trait; - /** - * Create a question object of a certain type, as defined in the helper.php file. - * - * @return qtype_formulas_question - */ - protected function get_test_formulas_question($which = null) { - return test_question_maker::make_question('formulas', $which); - } - /** * Data provider. * @@ -601,4 +591,116 @@ public function test_restore_quiz_with_same_stamp_questions_edited_hints(string $this->assertEquals($quiz1structure[1]->questionid, $quiz2structure[1]->questionid); $this->assertEquals($quiz1structure[2]->questionid, $quiz2structure[2]->questionid); } + + /** + * Data provider. + * + * @return array + */ + public static function provide_edited_option_fields(): array { + return [ + ['varsrandom', 'a={1,2,3};'], + ['varsglobal', 'b=1;'], + ['answernumbering', 'ABC'], + ['shownumcorrect', '0'], + ['correctfeedback', 'edited'], + ['partiallycorrectfeedback', 'edited'], + ['incorrectfeedback', 'edited'], + + ['answermark', '5'], + ['answertype', '100'], + ['vars1', 'c=5;'], + ['vars2', 'd=9;'], + ['correctness', '_err < 0.01'], + ['answer', '17'], + ['answernotunique', '0'], + ['unitpenalty', '0.5'], + ['postunit', 'm'], + ['ruleid', '2'], + ['otherrule', '60 s = 1 min'], + ['subqtext', 'edited'], + ['feedback', 'edited'], + ['partcorrectfb', 'edited'], + ['partpartiallycorrectfb', 'edited'], + ['partincorrectfb', 'edited'], + ]; + } + + /** + * Restore a quiz with questions of same stamp into the same course, but different qtype-specific options. + * + * @param string $field The answer field to edit + * @param string $value The value to set + * @dataProvider provide_edited_option_fields + */ + public function test_restore_quiz_with_same_stamp_questions_edited_options(string $field, string $value): void { + global $CFG, $DB, $USER; + $this->resetAfterTest(); + $this->setAdminUser(); + + // The changes introduced while fixing MDL-83541 are only present in Moodle 4.4 and newer. It + // does not make sense to perform this test with older versions. + if ($CFG->branch < 404) { + $this->markTestSkipped( + 'Not testing detection of duplicates while restoring in Moodle versions prior to 4.4.', + ); + } + + // Create a course and a user with editing teacher capabilities. + $generator = $this->getDataGenerator(); + $course1 = $generator->create_course(); + $teacher = $USER; + $generator->enrol_user($teacher->id, $course1->id, 'editingteacher'); + $coursecontext = \context_course::instance($course1->id); + /** @var \core_question_generator $questiongenerator */ + $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); + + // Create a question category. + $cat = $questiongenerator->create_question_category(['contextid' => $coursecontext->id]); + + // A quiz with 2 multichoice questions. + $quiz1 = $this->create_test_quiz($course1); + $question1 = $questiongenerator->create_question('formulas', 'testsinglenum', ['category' => $cat->id]); + quiz_add_quiz_question($question1->id, $quiz1, 0); + + $question2 = $questiongenerator->create_question('formulas', 'testsinglenum', ['category' => $cat->id]); + quiz_add_quiz_question($question2->id, $quiz1, 0); + + // Update question2 to have the same stamp as question1. + $DB->set_field('question', 'stamp', $question1->stamp, ['id' => $question2->id]); + + // Change the options of question2 to be different to question1. + $optionfields = ['varsrandom', 'varsglobal', 'answernumbering', 'shownumcorrect', 'correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback']; + if (in_array($field, $optionfields)) { + $DB->set_field('qtype_formulas_options', $field, $value, ['questionid' => $question2->id]); + } else { + $DB->set_field('qtype_formulas_answers', $field, $value, ['questionid' => $question2->id]); + } + + // Backup quiz. + $bc = new backup_controller(backup::TYPE_1ACTIVITY, $quiz1->cmid, backup::FORMAT_MOODLE, + backup::INTERACTIVE_NO, backup::MODE_IMPORT, $teacher->id); + $backupid = $bc->get_backupid(); + $bc->execute_plan(); + $bc->destroy(); + + // Restore the backup into the same course. + $rc = new restore_controller($backupid, $course1->id, backup::INTERACTIVE_NO, backup::MODE_IMPORT, + $teacher->id, backup::TARGET_CURRENT_ADDING); + $rc->execute_precheck(); + $rc->execute_plan(); + $rc->destroy(); + + // Verify that the newly-restored quiz questions match their quiz1 counterparts. + $modules = get_fast_modinfo($course1->id)->get_instances_of('quiz'); + $this->assertCount(2, $modules); + $quiz1structure = \mod_quiz\question\bank\qbank_helper::get_question_structure( + $quiz1->id, + \context_module::instance($quiz1->cmid), + ); + $quiz2 = end($modules); + $quiz2structure = \mod_quiz\question\bank\qbank_helper::get_question_structure($quiz2->instance, $quiz2->context); + $this->assertEquals($quiz1structure[1]->questionid, $quiz2structure[1]->questionid); + $this->assertEquals($quiz1structure[2]->questionid, $quiz2structure[2]->questionid); + } }