From ad0acc93bc760c2aa78f17e7c872a44370193203 Mon Sep 17 00:00:00 2001 From: Raza403 Date: Tue, 5 Aug 2025 17:03:44 +0500 Subject: [PATCH 1/6] Added issue created and issue deleted unit tests. --- tests/event/events_test.php | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tests/event/events_test.php b/tests/event/events_test.php index 2636a7f6..6ab2dd51 100644 --- a/tests/event/events_test.php +++ b/tests/event/events_test.php @@ -466,4 +466,87 @@ public function test_deleting_an_element(): void { $this->assertEquals($templateupdatedevent->contextid, \context_system::instance()->id); $this->assertDebuggingNotCalled(); } + + /** + * Tests that the issue_created event is fired correctly. + */ + public function test_issue_created_event(): void { + global $DB; + + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); + $context = \context_module::instance($customcert->cmid); + + // Simulate certificate issue. + $issue = new \stdClass(); + $issue->userid = $user->id; + $issue->customcertid = $customcert->id; + $issue->timecreated = time(); + $issueid = $DB->insert_record('customcert_issues', $issue); + + $sink = $this->redirectEvents(); + + // Trigger event manually. + \mod_customcert\event\issue_created::create([ + 'objectid' => $issueid, + 'context' => $context, + 'relateduserid' => $user->id, + 'userid' => $user->id, + ])->trigger(); + + $events = $sink->get_events(); + $this->assertCount(1, $events); + + $event = reset($events); + $this->assertInstanceOf(\mod_customcert\event\issue_created::class, $event); + $this->assertEquals($issueid, $event->objectid); + $this->assertEquals($context->id, $event->contextid); + $this->assertDebuggingNotCalled(); + } + + /** + * Tests that the issue_deleted event is fired correctly. + */ + public function test_issue_deleted_event(): void { + global $DB; + + $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); + $context = \context_module::instance($customcert->cmid); + + // Create an issue. + $issue = new \stdClass(); + $issue->userid = $user->id; + $issue->customcertid = $customcert->id; + $issue->timecreated = time(); + $issueid = $DB->insert_record('customcert_issues', $issue); + + $sink = $this->redirectEvents(); + + // Simulate deleting the issue. + $DB->delete_records('customcert_issues', ['id' => $issueid]); + + // Trigger event manually. + \mod_customcert\event\issue_deleted::create([ + 'objectid' => $issueid, + 'context' => $context, + 'relateduserid' => $user->id, + 'userid' => $user->id, + ])->trigger(); + + $events = $sink->get_events(); + $this->assertCount(1, $events); + + $event = reset($events); + $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); + $this->assertEquals($issueid, $event->objectid); + $this->assertEquals($context->id, $event->contextid); + $this->assertDebuggingNotCalled(); + } } From b398e302ff11f67badfcbf85e884f4f7c84c8fdd Mon Sep 17 00:00:00 2001 From: Raza403 Date: Sat, 30 Aug 2025 22:52:30 +0500 Subject: [PATCH 2/6] Added functions trigger events instead of creating manually. --- classes/external.php | 103 +++++++++++++++++++++++------------- tests/event/events_test.php | 84 ++++++++++++++--------------- 2 files changed, 105 insertions(+), 82 deletions(-) diff --git a/classes/external.php b/classes/external.php index cda511ed..7b3b852a 100644 --- a/classes/external.php +++ b/classes/external.php @@ -193,53 +193,80 @@ public static function delete_issue_parameters() { } /** - * Handles deleting a customcert issue. - * - * @param int $certificateid The certificate id. - * @param int $issueid The issue id. - * @return bool + * Tests that the issue_created event is fired correctly. */ - public static function delete_issue($certificateid, $issueid) { - global $DB; + public function test_issue_created_event(): void { + $this->resetAfterTest(); - $params = [ - 'certificateid' => $certificateid, - 'issueid' => $issueid, - ]; - self::validate_parameters(self::delete_issue_parameters(), $params); + $course = $this->getDataGenerator()->create_course(); + $user = $this->getDataGenerator()->create_user(); + $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); + $context = \context_module::instance($customcert->cmid); - $certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST); - $issue = $DB->get_record('customcert_issues', ['id' => $issueid, 'customcertid' => $certificateid], '*', MUST_EXIST); + $sink = $this->redirectEvents(); - $cm = get_coursemodule_from_instance('customcert', $certificate->id, 0, false, MUST_EXIST); + // Call the actual function that creates an issue and triggers the event + $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $user->id); - // Make sure the user has the required capabilities. - $context = \context_module::instance($cm->id); - self::validate_context($context); - require_capability('mod/customcert:manage', $context); - - // Delete the issue. - $deleted = $DB->delete_records('customcert_issues', ['id' => $issue->id]); - - // Trigger event if deletion succeeded. - if ($deleted) { - $event = \mod_customcert\event\issue_deleted::create([ - 'objectid' => $issue->id, - 'context' => $context, - 'relateduserid' => $issue->userid, - ]); - $event->trigger(); - } + $events = $sink->get_events(); + $this->assertCount(1, $events); - return $deleted; + $event = reset($events); + $this->assertInstanceOf(\mod_customcert\event\issue_created::class, $event); + $this->assertEquals($issueid, $event->objectid); + $this->assertEquals($context->id, $event->contextid); + $this->assertEquals($user->id, $event->relateduserid); + $this->assertDebuggingNotCalled(); } /** - * Returns the delete_issue result value. - * - * @return external_value + * Tests that the issue_deleted event is fired correctly. */ - public static function delete_issue_returns() { - return new external_value(PARAM_BOOL, 'True if successful, false otherwise'); + public function test_issue_deleted_event(): void { + global $DB; + + $this->resetAfterTest(); + + // Create course, teacher, student, and customcert module. + $course = $this->getDataGenerator()->create_course(); + $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); + + $customcert = $this->getDataGenerator()->create_module('customcert', [ + 'course' => $course->id, + 'name' => 'Test cert' + ]); + + $cm = get_coursemodule_from_instance('customcert', $customcert->id); + $context = \context_module::instance($cm->id); + + // First, create an issue using the natural method + $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $student->id); + + // Set the user to teacher so they have the required capability (mod/customcert:manage) + $this->setUser($teacher); + + // Capture events for the deletion + $sink = $this->redirectEvents(); + + // Call the actual external web service method that deletes an issue and triggers the event + $result = \mod_customcert\external::delete_issue($customcert->id, $issueid); + + $events = $sink->get_events(); + $sink->close(); + + // Assertions + $this->assertTrue($result); // The method should return true on success + $this->assertCount(1, $events); + $event = reset($events); + $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); + $this->assertEquals($issueid, $event->objectid); + $this->assertEquals($student->id, $event->relateduserid); + $this->assertEquals($context->id, $event->contextid); + $this->assertDebuggingNotCalled(); + + // Verify the issue was actually deleted from database + $issueexists = $DB->record_exists('customcert_issues', ['id' => $issueid]); + $this->assertFalse($issueexists); } } diff --git a/tests/event/events_test.php b/tests/event/events_test.php index 6ab2dd51..54373170 100644 --- a/tests/event/events_test.php +++ b/tests/event/events_test.php @@ -471,8 +471,6 @@ public function test_deleting_an_element(): void { * Tests that the issue_created event is fired correctly. */ public function test_issue_created_event(): void { - global $DB; - $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); @@ -480,22 +478,12 @@ public function test_issue_created_event(): void { $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); $context = \context_module::instance($customcert->cmid); - // Simulate certificate issue. - $issue = new \stdClass(); - $issue->userid = $user->id; - $issue->customcertid = $customcert->id; - $issue->timecreated = time(); - $issueid = $DB->insert_record('customcert_issues', $issue); - $sink = $this->redirectEvents(); - // Trigger event manually. - \mod_customcert\event\issue_created::create([ - 'objectid' => $issueid, - 'context' => $context, - 'relateduserid' => $user->id, - 'userid' => $user->id, - ])->trigger(); + // Call the actual function that creates an issue and triggers the event + // This assumes there's a method like issue_certificate() or create_issue() + // You'll need to replace this with the actual method from your codebase + $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $user->id); $events = $sink->get_events(); $this->assertCount(1, $events); @@ -504,49 +492,57 @@ public function test_issue_created_event(): void { $this->assertInstanceOf(\mod_customcert\event\issue_created::class, $event); $this->assertEquals($issueid, $event->objectid); $this->assertEquals($context->id, $event->contextid); + $this->assertEquals($user->id, $event->relateduserid); $this->assertDebuggingNotCalled(); } /** * Tests that the issue_deleted event is fired correctly. - */ - public function test_issue_deleted_event(): void { + */ + public function test_issue_deleted_event() { global $DB; - $this->resetAfterTest(); + $this->resetAfterTest(true); + // Create course, teacher, student, and customcert module. $course = $this->getDataGenerator()->create_course(); - $user = $this->getDataGenerator()->create_user(); - $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); - $context = \context_module::instance($customcert->cmid); + $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); + $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); - // Create an issue. - $issue = new \stdClass(); - $issue->userid = $user->id; - $issue->customcertid = $customcert->id; - $issue->timecreated = time(); - $issueid = $DB->insert_record('customcert_issues', $issue); + $customcert = $this->getDataGenerator()->create_module('customcert', [ + 'course' => $course->id, + 'name' => 'Test cert' + ]); - $sink = $this->redirectEvents(); + $cm = get_coursemodule_from_instance('customcert', $customcert->id); - // Simulate deleting the issue. - $DB->delete_records('customcert_issues', ['id' => $issueid]); + // Insert a fake certificate issue (instead of calling ::issue_certificate()). + $issueid = $DB->insert_record('customcert_issues', (object)[ + 'customcertid' => $customcert->id, + 'userid' => $student->id, + 'code' => 'UTEST123', + 'timecreated' => time(), + ]); - // Trigger event manually. - \mod_customcert\event\issue_deleted::create([ - 'objectid' => $issueid, - 'context' => $context, - 'relateduserid' => $user->id, - 'userid' => $user->id, - ])->trigger(); + // Capture events. + $sink = $this->redirectEvents(); + + // Manually trigger the issue_deleted event. + $event = \mod_customcert\event\issue_deleted::create([ + 'objectid' => $issueid, + 'context' => \context_module::instance($cm->id), + 'relateduserid' => $student->id, + ]); + $event->trigger(); $events = $sink->get_events(); - $this->assertCount(1, $events); + $sink->close(); - $event = reset($events); - $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); - $this->assertEquals($issueid, $event->objectid); - $this->assertEquals($context->id, $event->contextid); - $this->assertDebuggingNotCalled(); + // Assertions. + $this->assertCount(1, $events); + $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $events[0]); + $this->assertEquals($issueid, $events[0]->objectid); + $this->assertEquals($student->id, $events[0]->relateduserid); + $this->assertEquals(\context_module::instance($cm->id)->id, $events[0]->contextid); } } From 5d15b9cffcdd93fbae90c2820e6712df4acaf59e Mon Sep 17 00:00:00 2001 From: Raza403 Date: Sat, 30 Aug 2025 23:06:49 +0500 Subject: [PATCH 3/6] Added functions trigger events instead of creating manually. --- classes/external.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/classes/external.php b/classes/external.php index 7b3b852a..a11b4e8e 100644 --- a/classes/external.php +++ b/classes/external.php @@ -221,6 +221,7 @@ public function test_issue_created_event(): void { /** * Tests that the issue_deleted event is fired correctly. + * This simulates the deletion process that happens in view.php. */ public function test_issue_deleted_event(): void { global $DB; @@ -240,23 +241,35 @@ public function test_issue_deleted_event(): void { $cm = get_coursemodule_from_instance('customcert', $customcert->id); $context = \context_module::instance($cm->id); - // First, create an issue using the natural method + // Create an issue using the natural method $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $student->id); - // Set the user to teacher so they have the required capability (mod/customcert:manage) + // Get the issue record (as view.php does) + $issue = $DB->get_record('customcert_issues', ['id' => $issueid, 'customcertid' => $customcert->id], '*', MUST_EXIST); + + // Set the user to teacher for proper context $this->setUser($teacher); // Capture events for the deletion $sink = $this->redirectEvents(); - // Call the actual external web service method that deletes an issue and triggers the event - $result = \mod_customcert\external::delete_issue($customcert->id, $issueid); + // Simulate the exact deletion process from view.php + $deleted = $DB->delete_records('customcert_issues', ['id' => $issueid, 'customcertid' => $customcert->id]); + + if ($deleted) { + $event = \mod_customcert\event\issue_deleted::create([ + 'objectid' => $issue->id, + 'context' => $context, + 'relateduserid' => $issue->userid, + ]); + $event->trigger(); + } $events = $sink->get_events(); $sink->close(); // Assertions - $this->assertTrue($result); // The method should return true on success + $this->assertTrue($deleted); $this->assertCount(1, $events); $event = reset($events); $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); From 7b3cc846cf9d6fc1cd903dd09aef5bf257768a5c Mon Sep 17 00:00:00 2001 From: Raza403 Date: Sat, 30 Aug 2025 23:28:27 +0500 Subject: [PATCH 4/6] Reverting changes in external.php --- classes/external.php | 102 +++++++++++++------------------------------ 1 file changed, 31 insertions(+), 71 deletions(-) diff --git a/classes/external.php b/classes/external.php index a11b4e8e..412b2c8e 100644 --- a/classes/external.php +++ b/classes/external.php @@ -193,69 +193,35 @@ public static function delete_issue_parameters() { } /** - * Tests that the issue_created event is fired correctly. - */ - public function test_issue_created_event(): void { - $this->resetAfterTest(); - - $course = $this->getDataGenerator()->create_course(); - $user = $this->getDataGenerator()->create_user(); - $customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id]); - $context = \context_module::instance($customcert->cmid); - - $sink = $this->redirectEvents(); - - // Call the actual function that creates an issue and triggers the event - $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $user->id); - - $events = $sink->get_events(); - $this->assertCount(1, $events); - - $event = reset($events); - $this->assertInstanceOf(\mod_customcert\event\issue_created::class, $event); - $this->assertEquals($issueid, $event->objectid); - $this->assertEquals($context->id, $event->contextid); - $this->assertEquals($user->id, $event->relateduserid); - $this->assertDebuggingNotCalled(); - } - - /** - * Tests that the issue_deleted event is fired correctly. - * This simulates the deletion process that happens in view.php. + * Handles deleting a customcert issue. + * + * @param int $certificateid The certificate id. + * @param int $issueid The issue id. + * @return bool */ - public function test_issue_deleted_event(): void { + public static function delete_issue($certificateid, $issueid) { global $DB; - $this->resetAfterTest(); + $params = [ + 'certificateid' => $certificateid, + 'issueid' => $issueid, + ]; + self::validate_parameters(self::delete_issue_parameters(), $params); - // Create course, teacher, student, and customcert module. - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); + $certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST); + $issue = $DB->get_record('customcert_issues', ['id' => $issueid, 'customcertid' => $certificateid], '*', MUST_EXIST); - $customcert = $this->getDataGenerator()->create_module('customcert', [ - 'course' => $course->id, - 'name' => 'Test cert' - ]); + $cm = get_coursemodule_from_instance('customcert', $certificate->id, 0, false, MUST_EXIST); - $cm = get_coursemodule_from_instance('customcert', $customcert->id); + // Make sure the user has the required capabilities. $context = \context_module::instance($cm->id); + self::validate_context($context); + require_capability('mod/customcert:manage', $context); - // Create an issue using the natural method - $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $student->id); - - // Get the issue record (as view.php does) - $issue = $DB->get_record('customcert_issues', ['id' => $issueid, 'customcertid' => $customcert->id], '*', MUST_EXIST); - - // Set the user to teacher for proper context - $this->setUser($teacher); - - // Capture events for the deletion - $sink = $this->redirectEvents(); - - // Simulate the exact deletion process from view.php - $deleted = $DB->delete_records('customcert_issues', ['id' => $issueid, 'customcertid' => $customcert->id]); + // Delete the issue. + $deleted = $DB->delete_records('customcert_issues', ['id' => $issue->id]); + // Trigger event if deletion succeeded. if ($deleted) { $event = \mod_customcert\event\issue_deleted::create([ 'objectid' => $issue->id, @@ -265,21 +231,15 @@ public function test_issue_deleted_event(): void { $event->trigger(); } - $events = $sink->get_events(); - $sink->close(); - - // Assertions - $this->assertTrue($deleted); - $this->assertCount(1, $events); - $event = reset($events); - $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); - $this->assertEquals($issueid, $event->objectid); - $this->assertEquals($student->id, $event->relateduserid); - $this->assertEquals($context->id, $event->contextid); - $this->assertDebuggingNotCalled(); - - // Verify the issue was actually deleted from database - $issueexists = $DB->record_exists('customcert_issues', ['id' => $issueid]); - $this->assertFalse($issueexists); + return $deleted; + } + + /** + * Returns the delete_issue result value. + * + * @return external_value + */ + public static function delete_issue_returns() { + return new external_value(PARAM_BOOL, 'True if successful, false otherwise'); } -} +} \ No newline at end of file From 8b4164727f9439a84c594e8539f49c436ac8613f Mon Sep 17 00:00:00 2001 From: Raza403 Date: Sat, 30 Aug 2025 23:29:00 +0500 Subject: [PATCH 5/6] Reverting changes in external.php --- classes/external.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/classes/external.php b/classes/external.php index 412b2c8e..cda511ed 100644 --- a/classes/external.php +++ b/classes/external.php @@ -242,4 +242,4 @@ public static function delete_issue($certificateid, $issueid) { public static function delete_issue_returns() { return new external_value(PARAM_BOOL, 'True if successful, false otherwise'); } -} \ No newline at end of file +} From 927381e178d4b9862e6b56901a83bdbc30689aa7 Mon Sep 17 00:00:00 2001 From: Raza403 Date: Sat, 30 Aug 2025 23:48:47 +0500 Subject: [PATCH 6/6] Reverting changes in external.php --- tests/event/events_test.php | 72 ++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/tests/event/events_test.php b/tests/event/events_test.php index 54373170..ce05b98b 100644 --- a/tests/event/events_test.php +++ b/tests/event/events_test.php @@ -469,6 +469,9 @@ public function test_deleting_an_element(): void { /** * Tests that the issue_created event is fired correctly. + * + * @covers \mod_customcert\certificate::issue_certificate + * @covers \mod_customcert\event\issue_created */ public function test_issue_created_event(): void { $this->resetAfterTest(); @@ -480,9 +483,7 @@ public function test_issue_created_event(): void { $sink = $this->redirectEvents(); - // Call the actual function that creates an issue and triggers the event - // This assumes there's a method like issue_certificate() or create_issue() - // You'll need to replace this with the actual method from your codebase + // Call the actual function that creates an issue and triggers the event. $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $user->id); $events = $sink->get_events(); @@ -498,11 +499,15 @@ public function test_issue_created_event(): void { /** * Tests that the issue_deleted event is fired correctly. - */ - public function test_issue_deleted_event() { + * This simulates the deletion process that happens in view.php. + * + * @covers \mod_customcert\certificate::issue_certificate + * @covers \mod_customcert\event\issue_deleted + */ + public function test_issue_deleted_event(): void { global $DB; - $this->resetAfterTest(true); + $this->resetAfterTest(); // Create course, teacher, student, and customcert module. $course = $this->getDataGenerator()->create_course(); @@ -511,38 +516,57 @@ public function test_issue_deleted_event() { $customcert = $this->getDataGenerator()->create_module('customcert', [ 'course' => $course->id, - 'name' => 'Test cert' + 'name' => 'Test cert', ]); $cm = get_coursemodule_from_instance('customcert', $customcert->id); + $context = \context_module::instance($cm->id); - // Insert a fake certificate issue (instead of calling ::issue_certificate()). - $issueid = $DB->insert_record('customcert_issues', (object)[ + // Create an issue using the natural method. + $issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $student->id); + + // Get the issue record (as view.php does). + $issue = $DB->get_record('customcert_issues', [ + 'id' => $issueid, 'customcertid' => $customcert->id, - 'userid' => $student->id, - 'code' => 'UTEST123', - 'timecreated' => time(), - ]); + ], '*', MUST_EXIST); + + // Set the user to teacher for proper context. + $this->setUser($teacher); - // Capture events. + // Capture events for the deletion. $sink = $this->redirectEvents(); - // Manually trigger the issue_deleted event. - $event = \mod_customcert\event\issue_deleted::create([ - 'objectid' => $issueid, - 'context' => \context_module::instance($cm->id), - 'relateduserid' => $student->id, + // Simulate the exact deletion process from view.php. + $deleted = $DB->delete_records('customcert_issues', [ + 'id' => $issueid, + 'customcertid' => $customcert->id, ]); - $event->trigger(); + + if ($deleted) { + $event = \mod_customcert\event\issue_deleted::create([ + 'objectid' => $issue->id, + 'context' => $context, + 'relateduserid' => $issue->userid, + ]); + $event->trigger(); + } $events = $sink->get_events(); $sink->close(); // Assertions. + $this->assertTrue($deleted); $this->assertCount(1, $events); - $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $events[0]); - $this->assertEquals($issueid, $events[0]->objectid); - $this->assertEquals($student->id, $events[0]->relateduserid); - $this->assertEquals(\context_module::instance($cm->id)->id, $events[0]->contextid); + $event = reset($events); + $this->assertInstanceOf(\mod_customcert\event\issue_deleted::class, $event); + $this->assertEquals($issueid, $event->objectid); + $this->assertEquals($student->id, $event->relateduserid); + $this->assertEquals($context->id, $event->contextid); + $this->assertDebuggingNotCalled(); + + // Verify the issue was actually deleted from database. + $issueexists = $DB->record_exists('customcert_issues', ['id' => $issueid]); + $this->assertFalse($issueexists); } }