From 59cdf4341d037e1e10f265b6cc1250637d395901 Mon Sep 17 00:00:00 2001 From: hieuvu Date: Tue, 23 Dec 2025 15:15:18 +0700 Subject: [PATCH] MDL-87516 core_question: update behaviour when update question attempt. --- question/engine/datalib.php | 1 + question/engine/tests/datalib_test.php | 45 +++++++++++++++++++ .../tests/questionusage_autosave_test.php | 15 ++++--- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/question/engine/datalib.php b/question/engine/datalib.php index d645a760ea1..3377d4ac25b 100644 --- a/question/engine/datalib.php +++ b/question/engine/datalib.php @@ -941,6 +941,7 @@ ORDER BY $record = new stdClass(); $record->id = $qa->get_database_id(); $record->slot = $qa->get_slot(); + $record->behaviour = $qa->get_behaviour_name(); $record->questionid = $qa->get_question(false)->id; $record->variant = $qa->get_variant(); $record->maxmark = $qa->get_max_mark(); diff --git a/question/engine/tests/datalib_test.php b/question/engine/tests/datalib_test.php index f694a7066f5..fa273eb4184 100644 --- a/question/engine/tests/datalib_test.php +++ b/question/engine/tests/datalib_test.php @@ -279,6 +279,51 @@ final class datalib_test extends \qbehaviour_walkthrough_test_base { question_engine::save_questions_usage_by_activity($quba); } + /** + * Test replacing an old question attempt with a new question of a different behaviour. + * Ensures the slot is updated and the behaviour changes as expected. + * + * @covers ::add_question_in_place_of_other + */ + public function test_replace_old_attempt_with_a_question_have_different_behaviour(): void { + $this->resetAfterTest(); + + $generator = $this->getDataGenerator()->get_plugin_generator('core_question'); + $course = $this->getDataGenerator()->create_course(); + $qbank = $this->getDataGenerator()->create_module('qbank', ['course' => $course->id]); + $category = $generator->create_question_category( + ['contextid' => \context_module::instance($qbank->cmid)->id] + ); + // Create and add the initial question (true/false) to a new usage. + $truefalse = $generator->create_question('truefalse', null, ['category' => $category->id]); + $usage = \question_engine::make_questions_usage_by_activity('test', \context_module::instance($qbank->cmid)); + $usage->set_preferred_behaviour('deferredfeedback'); + $slot = $usage->add_question(question_bank::load_question($truefalse->id)); + $usage->start_all_questions(); + \question_engine::save_questions_usage_by_activity($usage); + + // Load the usage and get the current question in the slot. + $loadedusage = \question_engine::load_questions_usage_by_activity($usage->get_id()); + $originalquestion = $loadedusage->get_question_attempt($slot)->get_question(); + + // Create a new replacement question (description type). + $replacementquestion = \test_question_maker::make_question('description'); + + // Replace the question in the slot with the new one. + $newslot = $loadedusage->add_question_in_place_of_other($slot, $replacementquestion, null, false); + $loadedusage->start_question($newslot); + $loadedusage->finish_all_questions(); + \question_engine::save_questions_usage_by_activity($loadedusage); + + // Get the new question in the slot after replacement. + $newquestion = $loadedusage->get_question_attempt($newslot)->get_question(); + + // Check the replacement and behaviour. + $this->assertEquals($replacementquestion->name, $newquestion->name); + $this->assertNotEquals($originalquestion->id, $newquestion->id); + $this->assertEquals($loadedusage->get_question_attempt($newslot)->get_behaviour_name(), 'informationitem'); + } + /** * Test cases for {@see test_get_file_area_name()}. * diff --git a/question/engine/tests/questionusage_autosave_test.php b/question/engine/tests/questionusage_autosave_test.php index 939b5ab96e3..18e4b61c51d 100644 --- a/question/engine/tests/questionusage_autosave_test.php +++ b/question/engine/tests/questionusage_autosave_test.php @@ -562,9 +562,16 @@ final class questionusage_autosave_test extends \qbehaviour_walkthrough_test_bas $transaction->allow_commit(); // Now commit the other transaction. - $this->expectException('dml_write_exception'); - $this->save_quba($DB2); - $transaction2->allow_commit(); + try { + $this->save_quba($DB2); + // Should never get here. + $transaction2->allow_commit(); + } catch (\dml_write_exception $expected) { + // Testing the exception catch manually, because + // we want to assert some more things below. + } finally { + $DB2->dispose(); + } // Now re-load and check how that is re-displayed. $this->load_quba(); @@ -574,8 +581,6 @@ final class questionusage_autosave_test extends \qbehaviour_walkthrough_test_bas $this->render(); $this->check_output_contains_text_input('answer', 'autosaved response 1'); $this->check_output_contains_hidden_input(':sequencecheck', 1); - - $DB2->dispose(); } public function test_autosave_with_wrong_seq_number_ignored(): void {