2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
19 use core_question\question_reference_manager
;
20 use mod_quiz\question\display_options
;
22 defined('MOODLE_INTERNAL') ||
die();
25 require_once(__DIR__
. '/quiz_question_helper_test_trait.php');
26 require_once($CFG->dirroot
. '/backup/util/includes/restore_includes.php');
27 require_once($CFG->dirroot
. '/mod/quiz/locallib.php');
30 * Quiz backup and restore tests.
34 * @copyright 2021 Catalyst IT Australia Pty Ltd
35 * @author Safat Shahin <safatshahin@catalyst-au.net>
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 * @coversDefaultClass \mod_quiz\question\bank\qbank_helper
38 * @coversDefaultClass \backup_quiz_activity_structure_step
39 * @coversDefaultClass \restore_quiz_activity_structure_step
41 class quiz_question_restore_test
extends \advanced_testcase
{
42 use \quiz_question_helper_test_trait
;
45 * @var \stdClass test student user.
50 * Called before every test.
52 public function setUp(): void
{
55 $this->setAdminUser();
56 $this->course
= $this->getDataGenerator()->create_course();
57 $this->student
= $this->getDataGenerator()->create_user();
62 * Test a quiz backup and restore in a different course without attempts for course question bank.
64 * @covers ::get_question_structure
66 public function test_quiz_restore_in_a_different_course_using_course_question_bank() {
67 $this->resetAfterTest();
69 // Create the test quiz.
70 $quiz = $this->create_test_quiz($this->course
);
71 $oldquizcontext = \context_module
::instance($quiz->cmid
);
72 // Test for questions from a different context.
73 $coursecontext = \context_course
::instance($this->course
->id
);
74 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
75 $this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $coursecontext->id
]);
76 $this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $coursecontext->id
]);
79 $backupid = $this->backup_quiz($quiz, $this->user
);
81 // Delete the current course to make sure there is no data.
82 delete_course($this->course
, false);
84 // Check if the questions and associated data are deleted properly.
85 $this->assertEquals(0, count(\mod_quiz\question\bank\qbank_helper
::get_question_structure(
86 $quiz->id
, $oldquizcontext)));
88 // Restore the course.
89 $newcourse = $this->getDataGenerator()->create_course();
90 $this->restore_quiz($backupid, $newcourse, $this->user
);
93 $modules = get_fast_modinfo($newcourse->id
)->get_instances_of('quiz');
94 $module = reset($modules);
95 $questions = \mod_quiz\question\bank\qbank_helper
::get_question_structure(
96 $module->instance
, $module->context
);
97 $this->assertCount(3, $questions);
101 * Test a quiz backup and restore in a different course without attempts for quiz question bank.
103 * @covers ::get_question_structure
105 public function test_quiz_restore_in_a_different_course_using_quiz_question_bank() {
106 $this->resetAfterTest();
108 // Create the test quiz.
109 $quiz = $this->create_test_quiz($this->course
);
110 // Test for questions from a different context.
111 $quizcontext = \context_module
::instance($quiz->cmid
);
112 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
113 $this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $quizcontext->id
]);
114 $this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $quizcontext->id
]);
117 $backupid = $this->backup_quiz($quiz, $this->user
);
119 // Delete the current course to make sure there is no data.
120 delete_course($this->course
, false);
122 // Check if the questions and associated datas are deleted properly.
123 $this->assertEquals(0, count(\mod_quiz\question\bank\qbank_helper
::get_question_structure(
124 $quiz->id
, $quizcontext)));
126 // Restore the course.
127 $newcourse = $this->getDataGenerator()->create_course();
128 $this->restore_quiz($backupid, $newcourse, $this->user
);
131 $modules = get_fast_modinfo($newcourse->id
)->get_instances_of('quiz');
132 $module = reset($modules);
133 $this->assertEquals(3, count(\mod_quiz\question\bank\qbank_helper
::get_question_structure(
134 $module->instance
, $module->context
)));
138 * Count the questions for the context.
140 * @param int $contextid
141 * @param string $extracondition
142 * @return int the number of questions.
144 protected function question_count(int $contextid, string $extracondition = ''): int {
146 return $DB->count_records_sql(
149 JOIN {question_versions} qv ON qv.questionid = q.id
150 JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
151 JOIN {question_categories} qc on qc.id = qbe.questioncategoryid
152 WHERE qc.contextid = ?
153 $extracondition", [$contextid]);
157 * Test if a duplicate does not duplicate questions in course question bank.
159 * @covers ::duplicate_module
161 public function test_quiz_duplicate_does_not_duplicate_course_question_bank_questions() {
162 $this->resetAfterTest();
163 $quiz = $this->create_test_quiz($this->course
);
164 // Test for questions from a different context.
165 $context = \context_course
::instance($this->course
->id
);
166 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
167 $this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $context->id
]);
168 $this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $context->id
]);
169 // Count the questions in course context.
170 $this->assertEquals(7, $this->question_count($context->id
));
171 $newquiz = $this->duplicate_quiz($this->course
, $quiz);
172 $this->assertEquals(7, $this->question_count($context->id
));
173 $context = \context_module
::instance($newquiz->id
);
174 // Count the questions in the quiz context.
175 $this->assertEquals(0, $this->question_count($context->id
));
179 * Test quiz duplicate for quiz question bank.
181 * @covers ::duplicate_module
183 public function test_quiz_duplicate_for_quiz_question_bank_questions() {
184 $this->resetAfterTest();
185 $quiz = $this->create_test_quiz($this->course
);
186 // Test for questions from a different context.
187 $context = \context_module
::instance($quiz->cmid
);
188 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
189 $this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $context->id
]);
190 $this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $context->id
]);
191 // Count the questions in course context.
192 $this->assertEquals(7, $this->question_count($context->id
));
193 $newquiz = $this->duplicate_quiz($this->course
, $quiz);
194 $this->assertEquals(7, $this->question_count($context->id
));
195 $context = \context_module
::instance($newquiz->id
);
196 // Count the questions in the quiz context.
197 $this->assertEquals(7, $this->question_count($context->id
));
201 * Test quiz restore with attempts.
203 * @covers ::get_question_structure
205 public function test_quiz_restore_with_attempts() {
206 $this->resetAfterTest();
209 $quiz = $this->create_test_quiz($this->course
);
210 $quizcontext = \context_module
::instance($quiz->cmid
);
211 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
212 $this->add_two_regular_questions($questiongenerator, $quiz, ['contextid' => $quizcontext->id
]);
213 $this->add_one_random_question($questiongenerator, $quiz, ['contextid' => $quizcontext->id
]);
215 // Attempt it as a student, and check.
216 /** @var \question_usage_by_activity $quba */
217 [, $quba] = $this->attempt_quiz($quiz, $this->student
);
218 $this->assertEquals(3, $quba->question_count());
219 $this->assertCount(1, quiz_get_user_attempts($quiz->id
, $this->student
->id
));
222 $backupid = $this->backup_quiz($quiz, $this->user
);
224 // Delete the current course to make sure there is no data.
225 delete_course($this->course
, false);
227 // Restore the backup.
228 $newcourse = $this->getDataGenerator()->create_course();
229 $this->restore_quiz($backupid, $newcourse, $this->user
);
232 $modules = get_fast_modinfo($newcourse->id
)->get_instances_of('quiz');
233 $module = reset($modules);
234 $this->assertCount(1, quiz_get_user_attempts($module->instance
, $this->student
->id
));
235 $this->assertCount(3, \mod_quiz\question\bank\qbank_helper
::get_question_structure(
236 $module->instance
, $module->context
));
240 * Test pre 4.0 quiz restore for regular questions.
242 * Also, for efficiency, tests restore of the review options.
244 * @covers ::process_quiz_question_legacy_instance
246 public function test_pre_4_quiz_restore_for_regular_questions() {
248 $this->resetAfterTest();
250 $backuppath = make_backup_temp_directory($backupid);
251 get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
252 __DIR__
. "/fixtures/moodle_28_quiz.mbz", $backuppath);
254 // Do the restore to new course with default settings.
255 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
256 $newcourseid = \restore_dbops
::create_new_course('Test fullname', 'Test shortname', $categoryid);
257 $rc = new \restore_controller
($backupid, $newcourseid, \backup
::INTERACTIVE_NO
, \backup
::MODE_GENERAL
, $USER->id
,
258 \backup
::TARGET_NEW_COURSE
);
260 $this->assertTrue($rc->execute_precheck());
264 // Get the information about the resulting course and check that it is set up correctly.
265 $modinfo = get_fast_modinfo($newcourseid);
266 $quiz = array_values($modinfo->get_instances_of('quiz'))[0];
267 $quizobj = \mod_quiz\quiz_settings
::create($quiz->instance
);
268 $structure = structure
::create_for_quiz($quizobj);
270 // Verify the restored review options setting.
271 $this->assertEquals(display_options
::DURING |
272 display_options
::IMMEDIATELY_AFTER |
273 display_options
::LATER_WHILE_OPEN |
274 display_options
::AFTER_CLOSE
, $quizobj->get_quiz()->reviewmaxmarks
);
276 // Are the correct slots returned?
277 $slots = $structure->get_slots();
278 $this->assertCount(2, $slots);
280 $quizobj->preload_questions();
281 $quizobj->load_questions();
282 $questions = $quizobj->get_questions();
283 $this->assertCount(2, $questions);
285 // Count the questions in quiz qbank.
286 $this->assertEquals(2, $this->question_count($quizobj->get_context()->id
));
290 * Test pre 4.0 quiz restore for random questions.
292 * @covers ::process_quiz_question_legacy_instance
294 public function test_pre_4_quiz_restore_for_random_questions() {
296 $this->resetAfterTest();
299 $backuppath = make_backup_temp_directory($backupid);
300 get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
301 __DIR__
. "/fixtures/random_by_tag_quiz.mbz", $backuppath);
303 // Do the restore to new course with default settings.
304 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
305 $newcourseid = \restore_dbops
::create_new_course('Test fullname', 'Test shortname', $categoryid);
306 $rc = new \restore_controller
($backupid, $newcourseid, \backup
::INTERACTIVE_NO
, \backup
::MODE_GENERAL
, $USER->id
,
307 \backup
::TARGET_NEW_COURSE
);
309 $this->assertTrue($rc->execute_precheck());
313 // Get the information about the resulting course and check that it is set up correctly.
314 $modinfo = get_fast_modinfo($newcourseid);
315 $quiz = array_values($modinfo->get_instances_of('quiz'))[0];
316 $quizobj = \mod_quiz\quiz_settings
::create($quiz->instance
);
317 $structure = structure
::create_for_quiz($quizobj);
319 // Are the correct slots returned?
320 $slots = $structure->get_slots();
321 $this->assertCount(1, $slots);
323 $quizobj->preload_questions();
324 $quizobj->load_questions();
325 $questions = $quizobj->get_questions();
326 $this->assertCount(1, $questions);
328 // Count the questions for course question bank.
329 $this->assertEquals(6, $this->question_count(\context_course
::instance($newcourseid)->id
));
330 $this->assertEquals(6, $this->question_count(\context_course
::instance($newcourseid)->id
,
331 "AND q.qtype <> 'random'"));
333 // Count the questions in quiz qbank.
334 $this->assertEquals(0, $this->question_count($quizobj->get_context()->id
));
338 * Test pre 4.0 quiz restore for random question tags.
340 * @covers ::process_quiz_question_legacy_instance
342 public function test_pre_4_quiz_restore_for_random_question_tags() {
344 $this->resetAfterTest();
346 '1' => ['first question', 'one', 'number one'],
347 '2' => ['first question', 'one', 'number one'],
348 '3' => ['one', 'number one', 'second question'],
351 $backuppath = make_backup_temp_directory($backupid);
352 get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
353 __DIR__
. "/fixtures/moodle_311_quiz.mbz", $backuppath);
355 // Do the restore to new course with default settings.
356 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
357 $newcourseid = \restore_dbops
::create_new_course('Test fullname', 'Test shortname', $categoryid);
358 $rc = new \restore_controller
($backupid, $newcourseid, \backup
::INTERACTIVE_NO
, \backup
::MODE_GENERAL
, $USER->id
,
359 \backup
::TARGET_NEW_COURSE
);
361 $this->assertTrue($rc->execute_precheck());
365 // Get the information about the resulting course and check that it is set up correctly.
366 $modinfo = get_fast_modinfo($newcourseid);
367 $quiz = array_values($modinfo->get_instances_of('quiz'))[0];
368 $quizobj = \mod_quiz\quiz_settings
::create($quiz->instance
);
369 $structure = \mod_quiz\structure
::create_for_quiz($quizobj);
371 // Count the questions in quiz qbank.
372 $context = \context_module
::instance(get_coursemodule_from_instance("quiz", $quizobj->get_quizid(), $newcourseid)->id
);
373 $this->assertEquals(2, $this->question_count($context->id
));
375 // Are the correct slots returned?
376 $slots = $structure->get_slots();
377 $this->assertCount(3, $slots);
379 // Check if the tags match with the actual restored data.
380 foreach ($slots as $slot) {
381 $setreference = $DB->get_record('question_set_references',
382 ['itemid' => $slot->id
, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
383 $filterconditions = json_decode($setreference->filtercondition
);
385 foreach ($filterconditions->tags
as $tagstring) {
386 $tag = explode(',', $tagstring);
389 $this->assertEquals([], array_diff($randomtags[$slot->slot
], $tags));
395 * Test pre 4.0 quiz restore for random question used on multiple quizzes.
397 * @covers ::process_quiz_question_legacy_instance
399 public function test_pre_4_quiz_restore_shared_random_question() {
401 $this->resetAfterTest();
404 $backuppath = make_backup_temp_directory($backupid);
405 get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
406 __DIR__
. "/fixtures/pre-40-shared-random-question.mbz", $backuppath);
408 // Do the restore to new course with default settings.
409 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
410 $newcourseid = \restore_dbops
::create_new_course('Test fullname', 'Test shortname', $categoryid);
411 $rc = new \restore_controller
($backupid, $newcourseid, \backup
::INTERACTIVE_NO
, \backup
::MODE_GENERAL
, $USER->id
,
412 \backup
::TARGET_NEW_COURSE
);
414 $this->assertTrue($rc->execute_precheck());
418 // Get the information about the resulting course and check that it is set up correctly.
419 // Each quiz should contain an instance of the random question.
420 $modinfo = get_fast_modinfo($newcourseid);
421 $quizzes = $modinfo->get_instances_of('quiz');
422 $this->assertCount(2, $quizzes);
423 foreach ($quizzes as $quiz) {
424 $quizobj = \mod_quiz\quiz_settings
::create($quiz->instance
);
425 $structure = structure
::create_for_quiz($quizobj);
427 // Are the correct slots returned?
428 $slots = $structure->get_slots();
429 $this->assertCount(1, $slots);
431 $quizobj->preload_questions();
432 $quizobj->load_questions();
433 $questions = $quizobj->get_questions();
434 $this->assertCount(1, $questions);
437 // Count the questions for course question bank.
438 // We should have a single question, the random question should have been deleted after the restore.
439 $this->assertEquals(1, $this->question_count(\context_course
::instance($newcourseid)->id
));
440 $this->assertEquals(1, $this->question_count(\context_course
::instance($newcourseid)->id
,
441 "AND q.qtype <> 'random'"));
443 // Count the questions in quiz qbank.
444 $this->assertEquals(0, $this->question_count($quizobj->get_context()->id
));
448 * Ensure that question slots are correctly backed up and restored with all properties.
450 * @covers \backup_quiz_activity_structure_step::define_structure()
453 public function test_backup_restore_question_slots(): void
{
454 $this->resetAfterTest(true);
456 $course1 = $this->getDataGenerator()->create_course();
457 $course2 = $this->getDataGenerator()->create_course();
459 $user1 = $this->getDataGenerator()->create_and_enrol($course1, 'editingteacher');
460 $this->getDataGenerator()->enrol_user($user1->id
, $course2->id
, 'editingteacher');
463 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz');
465 $quiz = $quizgenerator->create_instance(['course' => $course1->id
, 'questionsperpage' => 0, 'grade' => 100.0,
468 // Create some fixed and random questions.
469 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
471 $cat = $questiongenerator->create_question_category();
472 $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id
]);
473 $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id
]);
474 $matchq = $questiongenerator->create_question('match', null, ['category' => $cat->id
]);
475 $randomcat = $questiongenerator->create_question_category();
476 $questiongenerator->create_question('shortanswer', null, ['category' => $randomcat->id
]);
477 $questiongenerator->create_question('numerical', null, ['category' => $randomcat->id
]);
478 $questiongenerator->create_question('match', null, ['category' => $randomcat->id
]);
480 // Add them to the quiz.
481 quiz_add_quiz_question($saq->id
, $quiz, 1, 3);
482 quiz_add_quiz_question($numq->id
, $quiz, 2, 2);
483 quiz_add_quiz_question($matchq->id
, $quiz, 3, 1);
484 $this->add_random_questions($quiz->id
, 3, $randomcat->id
, 2);
486 $quizobj = quiz_settings
::create($quiz->id
, $user1->id
);
487 $originalstructure = \mod_quiz\structure
::create_for_quiz($quizobj);
489 // Set one slot to a non-default display number.
490 $originalslots = $originalstructure->get_slots();
491 $firstslot = reset($originalslots);
492 $originalstructure->update_slot_display_number($firstslot->id
, rand(5, 10));
494 // Set one slot to requireprevious.
495 $lastslot = end($originalslots);
496 $originalstructure->update_question_dependency($lastslot->id
, true);
498 // Backup and restore the quiz.
499 $backupid = $this->backup_quiz($quiz, $user1);
500 $this->restore_quiz($backupid, $course2, $user1);
502 // Ensure the restored slots match the original slots.
503 $modinfo = get_fast_modinfo($course2);
504 $quizzes = $modinfo->get_instances_of('quiz');
505 $restoredquiz = reset($quizzes);
506 $restoredquizobj = quiz_settings
::create($restoredquiz->instance
, $user1->id
);
507 $restoredstructure = \mod_quiz\structure
::create_for_quiz($restoredquizobj);
508 $restoredslots = array_values($restoredstructure->get_slots());
509 $originalstructure = \mod_quiz\structure
::create_for_quiz($quizobj);
510 $originalslots = array_values($originalstructure->get_slots());
511 foreach ($restoredslots as $key => $restoredslot) {
512 $originalslot = $originalslots[$key];
513 $this->assertEquals($originalslot->quizid
, $quiz->id
);
514 $this->assertEquals($restoredslot->quizid
, $restoredquiz->instance
);
515 $this->assertEquals($originalslot->slot
, $restoredslot->slot
);
516 $this->assertEquals($originalslot->page
, $restoredslot->page
);
517 $this->assertEquals($originalslot->displaynumber
, $restoredslot->displaynumber
);
518 $this->assertEquals($originalslot->requireprevious
, $restoredslot->requireprevious
);
519 $this->assertEquals($originalslot->maxmark
, $restoredslot->maxmark
);
524 * Test pre 4.3 quiz restore for random question filter conditions.
526 * @covers \restore_question_set_reference_data_trait::process_question_set_reference
528 public function test_pre_43_quiz_restore_for_random_question_filtercondition() {
530 $this->resetAfterTest();
532 $backuppath = make_backup_temp_directory($backupid);
533 get_file_packer('application/vnd.moodle.backup')->extract_to_pathname(
534 __DIR__
. "/fixtures/moodle_42_random_question.mbz", $backuppath);
536 // Do the restore to new course with default settings.
537 $categoryid = $DB->get_field_sql("SELECT MIN(id) FROM {course_categories}");
538 $newcourseid = \restore_dbops
::create_new_course('Test fullname', 'Test shortname', $categoryid);
539 $rc = new \restore_controller
($backupid, $newcourseid, \backup
::INTERACTIVE_NO
, \backup
::MODE_GENERAL
, $USER->id
,
540 \backup
::TARGET_NEW_COURSE
);
542 $this->assertTrue($rc->execute_precheck());
546 // Get the information about the resulting course and check that it is set up correctly.
547 $modinfo = get_fast_modinfo($newcourseid);
548 $quiz = array_values($modinfo->get_instances_of('quiz'))[0];
549 $quizobj = \mod_quiz\quiz_settings
::create($quiz->instance
);
550 $structure = \mod_quiz\structure
::create_for_quiz($quizobj);
552 // Count the questions in quiz qbank.
553 $context = \context_module
::instance(get_coursemodule_from_instance("quiz", $quizobj->get_quizid(), $newcourseid)->id
);
554 $this->assertEquals(2, $this->question_count($context->id
));
556 // Are the correct slots returned?
557 $slots = $structure->get_slots();
558 $this->assertCount(1, $slots);
560 // Check that the filtercondition now matches the 4.3 structure.
561 foreach ($slots as $slot) {
562 $setreference = $DB->get_record('question_set_references',
563 ['itemid' => $slot->id
, 'component' => 'mod_quiz', 'questionarea' => 'slot']);
564 $filterconditions = json_decode($setreference->filtercondition
, true);
565 $this->assertArrayHasKey('cat', $filterconditions);
566 $this->assertArrayHasKey('jointype', $filterconditions);
567 $this->assertArrayHasKey('qpage', $filterconditions);
568 $this->assertArrayHasKey('qperpage', $filterconditions);
569 $this->assertArrayHasKey('filter', $filterconditions);
570 $this->assertArrayHasKey('category', $filterconditions['filter']);
571 $this->assertArrayHasKey('qtagids', $filterconditions['filter']);
572 $this->assertArrayHasKey('filteroptions', $filterconditions['filter']['category']);
573 $this->assertArrayHasKey('includesubcategories', $filterconditions['filter']['category']['filteroptions']);
575 // MDL-79708: Bad filter conversion check.
576 $this->assertArrayNotHasKey('includesubcategories', $filterconditions['filter']['category']);
578 $this->assertArrayNotHasKey('questioncategoryid', $filterconditions);
579 $this->assertArrayNotHasKey('tags', $filterconditions);
580 $expectedtags = \core_tag_tag
::get_by_name_bulk(1, ['foo', 'bar']);
581 $expectedtagids = array_values(array_map(fn($expectedtag) => $expectedtag->id
, $expectedtags));
582 $this->assertEquals($expectedtagids, $filterconditions['filter']['qtagids']['values']);
583 $expectedcategory = $DB->get_record('question_categories', ['idnumber' => 'RAND']);
584 $this->assertEquals($expectedcategory->id
, $filterconditions['filter']['category']['values'][0]);
585 $expectedcat = implode(',', [$expectedcategory->id
, $expectedcategory->contextid
]);
586 $this->assertEquals($expectedcat, $filterconditions['cat']);
588 // MDL-79708: Try to convert already converted filter.
589 $filterconditionsold = $filterconditions;
590 $filterconditions = question_reference_manager
::convert_legacy_set_reference_filter_condition($filterconditions);
591 // Check that the filtercondition didn't change.
592 $this->assertEquals($filterconditionsold, $filterconditions);
594 // MDL-79708: Try to convert a filter with previously bad conversion.
595 $filterconditions['filter']['category']['includesubcategories'] = 0;
596 unset($filterconditions['filter']['category']['filteroptions']);
597 $filterconditions = question_reference_manager
::convert_legacy_set_reference_filter_condition($filterconditions);
598 $this->assertEquals($filterconditionsold, $filterconditions);