From 79c9ad6277fde23babcd56d3bd0b9664735ba490 Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Wed, 28 Feb 2018 15:04:34 +0800 Subject: [PATCH] MDL-61363 question: unit tests for question tags context change --- lib/tests/questionlib_test.php | 538 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 531 insertions(+), 7 deletions(-) diff --git a/lib/tests/questionlib_test.php b/lib/tests/questionlib_test.php index 85c22e2e5e7..ee793d90435 100644 --- a/lib/tests/questionlib_test.php +++ b/lib/tests/questionlib_test.php @@ -76,7 +76,10 @@ class core_questionlib_testcase extends advanced_testcase { $category = $this->getDataGenerator()->create_category(); // Create course. - $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); + $course = $this->getDataGenerator()->create_course(array( + 'numsections' => 5, + 'category' => $category->id + )); $options = array( 'course' => $course->id, @@ -88,12 +91,22 @@ class core_questionlib_testcase extends advanced_testcase { $qgen = $this->getDataGenerator()->get_plugin_generator('core_question'); - if ('course' == $type) { - $context = context_course::instance($course->id); - } else if ('category' == $type) { - $context = context_coursecat::instance($category->id); - } else { - $context = context_module::instance($quiz->cmid); + switch ($type) { + case 'course': + $context = context_course::instance($course->id); + break; + + case 'category': + $context = context_coursecat::instance($category->id); + break; + + case 'system': + $context = context_system::instance(); + break; + + default: + $context = context_module::instance($quiz->cmid); + break; } $qcat = $qgen->create_question_category(array('contextid' => $context->id)); @@ -780,4 +793,515 @@ class core_questionlib_testcase extends advanced_testcase { } } } + + /** + * question_move_question_tags_to_new_context should update all of the + * question tags contexts when they are moving down (from system to course + * category context). + */ + public function test_question_move_question_tags_to_new_context_system_to_course_cat_qtags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_coursecat::instance($category->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo', 'bar']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo', 'bar']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + // All of the tags should have their context id set to the new context. + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the question tags + * contexts when they are moving down (from system to course category context) + * but leave any tags in the course context where they are. + */ + public function test_question_move_question_tags_to_new_context_system_to_course_cat_qtags_and_course_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $newcontext = context_coursecat::instance($category->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + foreach ($tags as $tag) { + if ($tag->name == 'ctag') { + // Course tags should remain in the course context. + $this->assertEquals($coursecontext->id, $tag->taginstancecontextid); + } else { + // Other tags should be updated. + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the question + * contexts tags when they are moving up (from course category to system context). + */ + public function test_question_move_question_tags_to_new_context_course_cat_to_system_qtags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_system::instance(); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the course category context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo', 'bar']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo', 'bar']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + // All of the tags should have their context id set to the new context. + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the question + * tags contexts when they are moving up (from course category context to system + * context) but leave any tags in the course context where they are. + */ + public function test_question_move_question_tags_to_new_context_course_cat_to_system_qtags_and_course_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $newcontext = context_system::instance(); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + foreach ($tags as $tag) { + if ($tag->name == 'ctag') { + // Course tags should remain in the course context. + $this->assertEquals($coursecontext->id, $tag->taginstancecontextid); + } else { + // Other tags should be updated. + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + } + + /** + * question_move_question_tags_to_new_context should merge all tags into the course + * context when moving down from course category context into course context. + */ + public function test_question_move_question_tags_to_new_context_course_cat_to_coures_qtags_and_course_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $newcontext = $coursecontext; + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have 2 tags. + $this->assertCount(2, $tags); + + foreach ($tags as $tag) { + // All tags should be updated to the course context and merged in. + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should delete all of the tag + * instances from sibling courses when moving the context of a question down + * from a course category into a course context because the other courses will + * no longer have access to the question. + */ + public function test_question_move_question_tags_to_new_context_remove_other_course_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + // Create a sibling course. + $siblingcourse = $this->getDataGenerator()->create_course(['category' => $course->category]); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $siblingcoursecontext = context_course::instance($siblingcourse->id); + $newcontext = $coursecontext; + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the target course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + // Create tags in the sibling course context. These should be deleted as + // part of the move. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $siblingcoursecontext, ['stag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $siblingcoursecontext, ['stag']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have 2 tags, 'foo' and 'ctag'. + $this->assertCount(2, $tags); + + foreach ($tags as $tag) { + $tagname = $tag->name; + // The 'stag' should have been deleted because it's in a sibling + // course context. + $this->assertContains($tagname, ['foo', 'ctag']); + // All tags should be in the course context now. + $this->assertEquals($coursecontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the question + * tags to be the course category context when moving the tags from a course + * context to a course category context. + */ + public function test_question_move_question_tags_to_new_context_course_to_course_cat() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + // Moving up into the course category context. + $newcontext = context_coursecat::instance($category->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + // All of the tags should have their context id set to the new context. + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the + * question tags contexts when they are moving down (from system to course + * category context). + */ + public function test_question_move_question_tags_to_new_context_orphaned_tag_contexts() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $othercategory = $this->getDataGenerator()->create_category(); + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_coursecat::instance($category->id); + $othercategorycontext = context_coursecat::instance($othercategory->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the other course category context. These should be + // update to the next context id because they represent erroneous data + // from a time before context id was mandatory in the tag API. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercategorycontext, ['bar']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercategorycontext, ['bar']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have two tags, 'foo' and 'bar'. + $this->assertCount(2, $tags); + + // All of the tags should have their context id set to the new context + // (course category context). + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * When moving from a course category context down into an activity context + * all question context tags and course tags (where the course is a parent of + * the activity) should move into the new context. + */ + public function test_question_move_question_tags_to_new_context_course_cat_to_activity_qtags_and_course_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $newcontext = context_module::instance($quiz->cmid); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the course category context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Move the questions to the activity context which is a child context of + // $coursecontext. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have 2 tags. + $this->assertCount(2, $tags); + + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * When moving from a course category context down into an activity context + * all question context tags and course tags (where the course is a parent of + * the activity) should move into the new context. Tags in course contexts + * that are not a parent of the activity context should be deleted. + */ + public function test_question_move_question_tags_to_new_context_course_cat_to_activity_orphaned_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('category'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $coursecontext = context_course::instance($course->id); + $newcontext = context_module::instance($quiz->cmid); + $othercourse = $this->getDataGenerator()->create_course(); + $othercoursecontext = context_course::instance($othercourse->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the course category context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['ctag']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['ctag']); + // Create tags in the other course context. These should be deleted. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercoursecontext, ['delete']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercoursecontext, ['delete']); + + // Move the questions to the activity context which is a child context of + // $coursecontext. + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have 2 tags. + $this->assertCount(2, $tags); + + foreach ($tags as $tag) { + // Make sure we don't have any 'delete' tags. + $this->assertContains($tag->name, ['foo', 'ctag']); + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * When moving from a course context down into an activity context all of the + * course tags should move into the activity context. + */ + public function test_question_move_question_tags_to_new_context_course_to_activity_qtags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('course'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_module::instance($quiz->cmid); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the course context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * When moving from a course context down into an activity context all of the + * course tags should move into the activity context. + */ + public function test_question_move_question_tags_to_new_context_activity_to_course_qtags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions(); + $question1 = $questions[0]; + $question2 = $questions[1]; + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_course::instance($course->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the activity context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + + foreach ($tags as $tag) { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } + } + } + + /** + * question_move_question_tags_to_new_context should update all of the + * question tags contexts when they are moving down (from system to course + * category context). + * + * Course tags within the new category context should remain while any course + * tags in course contexts that can no longer access the question should be + * deleted. + */ + public function test_question_move_question_tags_to_new_context_system_to_course_cat_with_orphaned_tags() { + list($category, $course, $quiz, $qcat, $questions) = $this->setup_quiz_and_questions('system'); + $question1 = $questions[0]; + $question2 = $questions[1]; + $othercategory = $this->getDataGenerator()->create_category(); + $othercourse = $this->getDataGenerator()->create_course(['category' => $othercategory->id]); + $qcontext = context::instance_by_id($qcat->contextid); + $newcontext = context_coursecat::instance($category->id); + $othercategorycontext = context_coursecat::instance($othercategory->id); + $coursecontext = context_course::instance($course->id); + $othercoursecontext = context_course::instance($othercourse->id); + + foreach ($questions as $question) { + $question->contextid = $qcat->contextid; + } + + // Create tags in the system context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $qcontext, ['foo']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $qcontext, ['foo']); + // Create tags in the child course context of the new context. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $coursecontext, ['bar']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $coursecontext, ['bar']); + // Create tags in the other course context. These should be deleted when + // the question moves to the new course category context because this + // course belongs to a different category, which means it will no longer + // have access to the question. + core_tag_tag::set_item_tags('core_question', 'question', $question1->id, $othercoursecontext, ['delete']); + core_tag_tag::set_item_tags('core_question', 'question', $question2->id, $othercoursecontext, ['delete']); + + question_move_question_tags_to_new_context($questions, $newcontext); + + foreach ($questions as $question) { + $tags = core_tag_tag::get_item_tags('core_question', 'question', $question->id); + // Each question should have two tags, 'foo' and 'bar'. + $this->assertCount(2, $tags); + + // All of the tags should have their context id set to the new context + // (course category context). + foreach ($tags as $tag) { + $this->assertContains($tag->name, ['foo', 'bar']); + + if ($tag->name == 'foo') { + $this->assertEquals($newcontext->id, $tag->taginstancecontextid); + } else { + $this->assertEquals($coursecontext->id, $tag->taginstancecontextid); + } + } + } + } } -- 2.11.4.GIT