From fd302dc84244e19dadfae04ae162d21cea072983 Mon Sep 17 00:00:00 2001 From: Michael Hawkins Date: Thu, 18 Mar 2021 14:27:36 +0800 Subject: [PATCH] MDL-71104 core_completion: Fix fetching of grade completion status We should be able to fetch the grade completion status for modules that do not have custom completion configured. This also improves unit testing coverage. --- lib/completionlib.php | 4 +- lib/tests/completionlib_test.php | 85 ++++++++++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lib/completionlib.php b/lib/completionlib.php index 5318a86df09..d39506ff4e5 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -1111,13 +1111,13 @@ class completion_info { $customdata = (array)$cm->customdata; // Return early if the plugin does not define custom completion rules. if (empty($customdata['customcompletionrules'])) { - return []; + return $data; } // Return early if the activity modules doe not implement the activity_custom_completion class. $cmcompletionclass = activity_custom_completion::get_cm_completion_class($cm->modname); if (!$cmcompletionclass) { - return []; + return $data; } /** @var activity_custom_completion $customcmcompletion */ diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php index 601f4214351..4065c74fcfd 100644 --- a/lib/tests/completionlib_test.php +++ b/lib/tests/completionlib_test.php @@ -619,17 +619,17 @@ class core_completionlib_testcase extends advanced_testcase { $this->setup_data(); $user = $this->user; - /** @var \mod_choice_generator $choicegenerator */ $choicegenerator = $this->getDataGenerator()->get_plugin_generator('mod_choice'); $choice = $choicegenerator->create_instance([ 'course' => $this->course->id, - 'completion' => true, + 'completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => true, + 'completionsubmit' => true, ]); $cm = get_coursemodule_from_instance('choice', $choice->id); - // Let's manually create a course completion record instead of going thru the hoops to complete an activity. + // Let's manually create a course completion record instead of going through the hoops to complete an activity. if ($hasrecord) { $cmcompletionrecord = (object)[ 'coursemoduleid' => $cm->id, @@ -656,6 +656,7 @@ class core_completionlib_testcase extends advanced_testcase { $completioninfo = new completion_info($this->course); $result = $completioninfo->get_data($cm, $wholecourse, $user->id); + // Course module ID of the returned completion data must match this activity's course module ID. $this->assertEquals($cm->id, $result->coursemoduleid); // User ID of the returned completion data must match the user's ID. @@ -687,6 +688,84 @@ class core_completionlib_testcase extends advanced_testcase { // Otherwise, this should not be cached. $this->assertFalse($cache->get($key)); } + + // Check that we are including relevant completion data for the module. + if (!$wholecourse) { + $this->assertTrue(property_exists($result, 'viewed')); + $this->assertTrue(property_exists($result, 'customcompletion')); + } + } + + /** + * Tests for completion_info::get_other_cm_completion_data(). + */ + public function test_get_other_cm_completion_data() { + global $DB; + + $this->setup_data(); + $user = $this->user; + + $this->setAdminUser(); + + $choicegenerator = $this->getDataGenerator()->get_plugin_generator('mod_choice'); + $choice = $choicegenerator->create_instance([ + 'course' => $this->course->id, + 'completion' => COMPLETION_TRACKING_AUTOMATIC, + 'completionsubmit' => true, + ]); + + $cmchoice = cm_info::create(get_coursemodule_from_instance('choice', $choice->id)); + + $choice2 = $choicegenerator->create_instance([ + 'course' => $this->course->id, + 'completion' => COMPLETION_TRACKING_AUTOMATIC, + ]); + + $cmchoice2 = cm_info::create(get_coursemodule_from_instance('choice', $choice2->id)); + + $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop'); + $workshop = $workshopgenerator->create_instance([ + 'course' => $this->course->id, + 'completion' => COMPLETION_TRACKING_AUTOMATIC, + // Submission grade required. + 'completiongradeitemnumber' => 0, + ]); + + $cmworkshop = cm_info::create(get_coursemodule_from_instance('workshop', $workshop->id)); + + $completioninfo = new completion_info($this->course); + + $method = new ReflectionMethod("completion_info", "get_other_cm_completion_data"); + $method->setAccessible(true); + + // Check that fetching data for a module with custom completion provides its info. + $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id); + + $this->assertArrayHasKey('customcompletion', $choicecompletiondata); + $this->assertArrayHasKey('completionsubmit', $choicecompletiondata['customcompletion']); + $this->assertEquals(COMPLETION_INCOMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']); + + // Mock a choice answer so user has completed the requirement. + $choicemockinfo = [ + 'choiceid' => $cmchoice->instance, + 'userid' => $this->user->id + ]; + $DB->insert_record('choice_answers', $choicemockinfo, false); + + // Confirm fetching again reflects the completion. + $choicecompletiondata = $method->invoke($completioninfo, $cmchoice, $user->id); + $this->assertEquals(COMPLETION_COMPLETE, $choicecompletiondata['customcompletion']['completionsubmit']); + + // Check that fetching data for a module with no custom completion still provides its grade completion status. + $workshopcompletiondata = $method->invoke($completioninfo, $cmworkshop, $user->id); + + $this->assertArrayHasKey('completiongrade', $workshopcompletiondata); + $this->assertArrayNotHasKey('customcompletion', $workshopcompletiondata); + $this->assertEquals(COMPLETION_INCOMPLETE, $workshopcompletiondata['completiongrade']); + + // Check that fetching data for a module with no completion conditions does not provide any data. + $choice2completiondata = $method->invoke($completioninfo, $cmchoice2, $user->id); + $this->assertEmpty($choice2completiondata); } public function test_internal_set_data() {