From a949a151f3bf51d085118a52e25f60b4d8b13151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mudr=C3=A1k?= Date: Tue, 18 May 2021 18:58:53 +0200 Subject: [PATCH] MDL-71659 completion: Consider modules without grade_item incomplete Activity modules may not have the associated grade_item created yet. It used to throw fatal error in that case - even when trying to view the course or edit the activity. So there was no easy way to recover from this situation. The patch is based on reasoning that an activity without grade item is same as activity without any grades. And as such it is considered incomplete. A new unit test is added to cover this specific scenario. The existing unit test is modified and it does not expect the exception any more. There does not seem to be any good reason why this situation should be exceptional. --- lib/completionlib.php | 3 --- lib/tests/completionlib_test.php | 40 +++++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/lib/completionlib.php b/lib/completionlib.php index 9154d28ad613a..66d6556b1ec04 100644 --- a/lib/completionlib.php +++ b/lib/completionlib.php @@ -769,9 +769,6 @@ public function get_grade_completion(cm_info $cm, int $userid): int { item '{$item->id}', user '{$userid}'"); } return self::internal_get_grade_state($item, reset($grades)); - } else { - $this->internal_systemerror("Cannot find grade item for '{$cm->modname}' - cm '{$cm->id}' matching number '{$cm->completiongradeitemnumber}'"); } return COMPLETION_INCOMPLETE; diff --git a/lib/tests/completionlib_test.php b/lib/tests/completionlib_test.php index aa7d567b75e33..a629f7b037ee9 100644 --- a/lib/tests/completionlib_test.php +++ b/lib/tests/completionlib_test.php @@ -1266,7 +1266,7 @@ public function test_completion_can_view_data() { */ public function get_grade_completion_provider() { return [ - 'Grade not required' => [false, false, null, moodle_exception::class, null], + 'Grade not required' => [false, false, null, null, null], 'Grade required, but has no grade yet' => [true, false, null, null, COMPLETION_INCOMPLETE], 'Grade required, grade received' => [true, true, null, null, COMPLETION_COMPLETE], 'Grade required, passing grade received' => [true, true, 70, null, COMPLETION_COMPLETE_PASS], @@ -1312,6 +1312,44 @@ public function test_get_grade_completion(bool $completionusegrade, bool $hasgra $gradecompletion = $completioninfo->get_grade_completion($cm, $this->user->id); $this->assertEquals($expectedresult, $gradecompletion); } + + /** + * Test the return value for cases when the activity module does not have associated grade_item. + */ + public function test_get_grade_completion_without_grade_item() { + global $DB; + + $this->setup_data(); + + $assign = $this->getDataGenerator()->get_plugin_generator('mod_assign')->create_instance([ + 'course' => $this->course->id, + 'completion' => COMPLETION_ENABLED, + 'completionusegrade' => true, + 'gradepass' => 42, + ]); + + $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign->id)); + + $DB->delete_records('grade_items', [ + 'courseid' => $this->course->id, + 'itemtype' => 'mod', + 'itemmodule' => 'assign', + 'iteminstance' => $assign->id, + ]); + + // Without the grade_item, the activity is considered incomplete. + $completioninfo = new completion_info($this->course); + $this->assertEquals(COMPLETION_INCOMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id)); + + // Once the activity is graded, the grade_item is automatically created. + $assigninstance = new assign($cm->context, $cm, $this->course); + $grade = $assigninstance->get_user_grade($this->user->id, true); + $grade->grade = 40; + $assigninstance->update_grade($grade); + + // The implicitly created grade_item does not have grade to pass defined so it is not distinguished. + $this->assertEquals(COMPLETION_COMPLETE, $completioninfo->get_grade_completion($cm, $this->user->id)); + } } class core_completionlib_fake_recordset implements Iterator {