ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/notes/tests/lib_test.php000064400000007136152266415050023506 0ustar00. /** * Tests for notes library functions. * * @package core_notes * @copyright 2015 onwards Ankit agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ namespace core_notes; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/notes/lib.php'); /** * Class core_notes_lib_testcase * * @package core_notes * @copyright 2015 onwards Ankit agarwal * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later. */ final class lib_test extends \advanced_testcase { /** * @var stdClass The user. */ private $user; /** * @var stdClass The course. */ private $course; /** * @var \core_user\output\myprofile\tree The navigation tree. */ private $tree; public function setUp(): void { parent::setUp(); $this->user = $this->getDataGenerator()->create_user(); $this->course = $this->getDataGenerator()->create_course(); $this->tree = new \core_user\output\myprofile\tree(); $this->resetAfterTest(); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation(): void { global $USER; // Set up the test. $this->setAdminUser(); $iscurrentuser = true; // Enable notes. set_config('enablenotes', true); // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $this->assertArrayHasKey('notes', $nodes->getValue($this->tree)); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation_as_guest(): void { global $USER; $this->setGuestUser(); $iscurrentuser = false; // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $this->assertArrayNotHasKey('notes', $nodes->getValue($this->tree)); } /** * Tests the core_notes_myprofile_navigation() function. */ public function test_core_notes_myprofile_navigation_notes_disabled(): void { global $USER; $this->setAdminUser(); $iscurrentuser = false; // Disable notes. set_config('enablenotes', false); // Check the node tree is correct. core_notes_myprofile_navigation($this->tree, $USER, $iscurrentuser, $this->course); $reflector = new \ReflectionObject($this->tree); $nodes = $reflector->getProperty('nodes'); $this->assertArrayNotHasKey('notes', $nodes->getValue($this->tree)); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/competency/tests/lib_test.php000064400000036143152266424560024532 0ustar00. /** * Lib tests. * * @package core_competency * @copyright 2015 Frédéric Massart - FMCorz.net * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_competency; defined('MOODLE_INTERNAL') || die(); use core_competency\plan; use core_competency\url; use core_competency\user_competency; global $CFG; /** * Lib testcase. * * @package core_competency * @copyright 2015 Frédéric Massart - FMCorz.net * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { public function test_comment_add_user_competency(): void { global $DB, $PAGE; $this->resetAfterTest(); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $u1 = $dg->create_user(['picture' => 1]); $u2 = $dg->create_user(); $u3 = $dg->create_user(); $reviewerroleid = $dg->create_role(); assign_capability('moodle/competency:planview', CAP_ALLOW, $reviewerroleid, \context_system::instance()->id, true); assign_capability('moodle/competency:usercompetencycomment', CAP_ALLOW, $reviewerroleid, \context_system::instance()->id, true); $dg->role_assign($reviewerroleid, $u2->id, \context_user::instance($u1->id)); $dg->role_assign($reviewerroleid, $u3->id, \context_user::instance($u1->id)); accesslib_clear_all_caches_for_unit_testing(); $f1 = $lpg->create_framework(); $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'))); // In 1 plan. $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'))); // In 2 plans. $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'))); // Orphan. $p1 = $lpg->create_plan(array('userid' => $u1->id)); $lpg->create_plan_competency(array('planid' => $p1->get('id'), 'competencyid' => $c1->get('id'))); $lpg->create_plan_competency(array('planid' => $p1->get('id'), 'competencyid' => $c2->get('id'))); $p2 = $lpg->create_plan(array('userid' => $u1->id)); $lpg->create_plan_competency(array('planid' => $p2->get('id'), 'competencyid' => $c2->get('id'))); $DB->set_field(plan::TABLE, 'timemodified', 1, array('id' => $p1->get('id'))); // Make plan 1 appear as old. $p1->read(); $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c1->get('id'), 'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $u2->id)); $uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c2->get('id'), 'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $u2->id)); $uc3 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c3->get('id'), 'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $u2->id)); // Post a comment for the user competency being in one plan. The reviewer is messaged. $this->setUser($u1); $comment = $uc1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = $c1->get('shortname'); $expectedurl = url::user_competency_in_plan($u1->id, $c1->get('id'), $p1->get('id')); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u2->id, $message->useridto); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); // Test customdata. $customdata = json_decode($message->customdata); $this->assertObjectHasProperty('notificationiconurl', $customdata); $this->assertStringContainsString('tokenpluginfile.php', $customdata->notificationiconurl); $userpicture = new \user_picture($u1); $userpicture->size = 1; // Use f1 size. $userpicture->includetoken = $u2->id; $this->assertEquals($userpicture->get_url($PAGE)->out(false), $customdata->notificationiconurl); // Reviewer posts a comment for the user competency being in two plans. Owner is messaged. $this->setUser($u2); $comment = $uc2->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = $c2->get('shortname'); $expectedurl = url::user_competency_in_plan($u1->id, $c2->get('id'), $p2->get('id')); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message->useridto); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); // Reviewer posts a comment for the user competency being in no plans. User is messaged. $this->setUser($u2); $comment = $uc3->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = get_string('userplans', 'core_competency'); $expectedurl = url::plans($u1->id); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message->useridto); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); // A comment is posted by another user, reviewer and owner are messaged. $this->setUser($u3); $comment = $uc3->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(2, $messages); $message1 = array_shift($messages); $message2 = array_shift($messages); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message1->useridto); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u2->id, $message2->useridto); // A comment is posted in HTML. $this->setUser($u2); $comment = $uc3->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!', FORMAT_HTML); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = get_string('userplans', 'core_competency'); $expectedurl = url::plans($u1->id); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message->useridto); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_HTML, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); } /** * Commenting on a plan. */ public function test_comment_add_plan(): void { $this->resetAfterTest(); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $u1 = $dg->create_user(); $u2 = $dg->create_user(); $u3 = $dg->create_user(); $userroleid = $dg->create_role(); $reviewerroleid = $dg->create_role(); assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $userroleid, \context_system::instance()->id, true); assign_capability('moodle/competency:planviewown', CAP_ALLOW, $userroleid, \context_system::instance()->id, true); assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $reviewerroleid, \context_system::instance()->id, true); assign_capability('moodle/competency:planmanage', CAP_ALLOW, $reviewerroleid, \context_system::instance()->id, true); assign_capability('moodle/competency:plancomment', CAP_ALLOW, $reviewerroleid, \context_system::instance()->id, true); $dg->role_assign($userroleid, $u1->id, \context_user::instance($u1->id)); $dg->role_assign($reviewerroleid, $u2->id, \context_user::instance($u1->id)); $dg->role_assign($reviewerroleid, $u3->id, \context_system::instance()); accesslib_clear_all_caches_for_unit_testing(); $p1 = $lpg->create_plan(array('userid' => $u1->id)); // Post a comment in own plan, no reviewer. Nobody is messaged. $this->setUser($u1); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(0, $messages); // Post a comment in plan as someone else, no reviewer. The owner is messages. $this->setUser($u3); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message->useridto); // Test customdata. $customdata = json_decode($message->customdata); $this->assertObjectHasProperty('notificationiconurl', $customdata); // Post a comment in a plan with reviewer. The reviewer is messaged. $p1->set('reviewerid', $u2->id); $p1->update(); $this->setUser($u1); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u2->id, $message->useridto); // Post a comment as reviewer in a plan being reviewed. The owner is messaged. $p1->set('reviewerid', $u2->id); $p1->update(); $this->setUser($u2); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $this->assertEquals(\core_user::get_noreply_user()->id, $message->useridfrom); $this->assertEquals($u1->id, $message->useridto); // Post a comment as someone else in a plan being reviewed. The owner and reviewer are messaged. $p1->set('reviewerid', $u2->id); $p1->update(); $this->setUser($u3); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(2, $messages); $message1 = array_shift($messages); $message2 = array_shift($messages); $this->assertEquals(\core_user::get_noreply_user()->id, $message1->useridfrom); $this->assertEquals($u1->id, $message1->useridto); $this->assertEquals(\core_user::get_noreply_user()->id, $message2->useridfrom); $this->assertEquals($u2->id, $message2->useridto); $p1->set('reviewerid', null); $p1->update(); // Test message content. $this->setUser($u3); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!'); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = $p1->get('name'); $expectedurl = url::plan($p1->get('id')); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); // Test message content as HTML. $this->setUser($u3); $comment = $p1->get_comment_object(); $sink = $this->redirectMessages(); $comment->add('Hello world!', FORMAT_HTML); $messages = $sink->get_messages(); $sink->close(); $this->assertCount(1, $messages); $message = array_pop($messages); $expectedurlname = $p1->get('name'); $expectedurl = url::plan($p1->get('id')); $this->assertTrue(strpos($message->fullmessage, 'Hello world!') !== false); $this->assertTrue(strpos($message->fullmessagehtml, 'Hello world!') !== false); $this->assertEquals(FORMAT_HTML, $message->fullmessageformat); $this->assertEquals($expectedurl->out(false), $message->contexturl); $this->assertEquals($expectedurlname, $message->contexturlname); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/cohort/tests/lib_test.php000064400000127473152266567240023674 0ustar00. namespace core_cohort; use core_cohort\customfield\cohort_handler; use core_customfield\data_controller; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once("$CFG->dirroot/cohort/lib.php"); /** * Cohort library tests. * * @package core_cohort * @category phpunit * @copyright 2012 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { /** * Create Cohort custom field for testing. * * @return \core_customfield\field_controller */ protected function create_cohort_custom_field(): \core_customfield\field_controller { $fieldcategory = self::getDataGenerator()->create_custom_field_category([ 'component' => 'core_cohort', 'area' => 'cohort', 'name' => 'Other fields', ]); return self::getDataGenerator()->create_custom_field([ 'shortname' => 'testfield1', 'name' => 'Custom field', 'type' => 'text', 'categoryid' => $fieldcategory->get('id'), ]); } public function test_cohort_add_cohort(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $this->create_cohort_custom_field(); $cohort = new \stdClass(); $cohort->contextid = \context_system::instance()->id; $cohort->name = 'test cohort'; $cohort->idnumber = 'testid'; $cohort->description = 'test cohort desc'; $cohort->descriptionformat = FORMAT_HTML; $cohort->customfield_testfield1 = 'Test value 1'; $id = cohort_add_cohort($cohort); $this->assertNotEmpty($id); $newcohort = $DB->get_record('cohort', array('id'=>$id)); $this->assertEquals($cohort->contextid, $newcohort->contextid); $this->assertSame($cohort->name, $newcohort->name); $this->assertSame($cohort->description, $newcohort->description); $this->assertEquals($cohort->descriptionformat, $newcohort->descriptionformat); $this->assertNotEmpty($newcohort->timecreated); $this->assertSame($newcohort->component, ''); $this->assertSame($newcohort->theme, ''); $this->assertSame($newcohort->timecreated, $newcohort->timemodified); $handler = cohort_handler::create(); $customfieldsdata = $handler->export_instance_data_object($id); $this->assertEquals('Test value 1', $customfieldsdata->testfield1); } public function test_cohort_add_cohort_missing_name(): void { $cohort = new \stdClass(); $cohort->contextid = \context_system::instance()->id; $cohort->name = null; $cohort->idnumber = 'testid'; $cohort->description = 'test cohort desc'; $cohort->descriptionformat = FORMAT_HTML; $this->expectException(\coding_exception::class); $this->expectExceptionMessage('Missing cohort name in cohort_add_cohort()'); cohort_add_cohort($cohort); } public function test_cohort_add_cohort_event(): void { $this->resetAfterTest(); // Setup cohort data structure. $cohort = new \stdClass(); $cohort->contextid = \context_system::instance()->id; $cohort->name = 'test cohort'; $cohort->idnumber = 'testid'; $cohort->description = 'test cohort desc'; $cohort->descriptionformat = FORMAT_HTML; // Catch Events. $sink = $this->redirectEvents(); // Perform the add operation. $id = cohort_add_cohort($cohort); // Capture the event. $events = $sink->get_events(); $sink->close(); // Validate the event. $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\core\event\cohort_created', $event); $this->assertEquals('cohort', $event->objecttable); $this->assertEquals($id, $event->objectid); $this->assertEquals($cohort->contextid, $event->contextid); $url = new \moodle_url('/cohort/index.php', array('contextid' => $event->contextid)); $this->assertEquals($url, $event->get_url()); $this->assertEquals($cohort, $event->get_record_snapshot('cohort', $id)); $this->assertEventContextNotUsed($event); } public function test_cohort_update_cohort(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $this->create_cohort_custom_field(); $cohort = new \stdClass(); $cohort->contextid = \context_system::instance()->id; $cohort->name = 'test cohort'; $cohort->idnumber = 'testid'; $cohort->description = 'test cohort desc'; $cohort->descriptionformat = FORMAT_HTML; $cohort->customfield_testfield1 = 'Test value 1'; $id = cohort_add_cohort($cohort); $this->assertNotEmpty($id); $DB->set_field('cohort', 'timecreated', $cohort->timecreated - 10, array('id'=>$id)); $DB->set_field('cohort', 'timemodified', $cohort->timemodified - 10, array('id'=>$id)); $cohort = $DB->get_record('cohort', array('id'=>$id)); $cohort->name = 'test cohort 2'; $cohort->customfield_testfield1 = 'Test value updated'; cohort_update_cohort($cohort); $newcohort = $DB->get_record('cohort', array('id'=>$id)); $this->assertSame($cohort->contextid, $newcohort->contextid); $this->assertSame($cohort->name, $newcohort->name); $this->assertSame($cohort->description, $newcohort->description); $this->assertSame($cohort->descriptionformat, $newcohort->descriptionformat); $this->assertSame($cohort->timecreated, $newcohort->timecreated); $this->assertSame($cohort->component, $newcohort->component); $this->assertSame($newcohort->theme, ''); $this->assertGreaterThan($newcohort->timecreated, $newcohort->timemodified); $this->assertLessThanOrEqual(time(), $newcohort->timemodified); $handler = cohort_handler::create(); $customfieldsdata = $handler->export_instance_data_object($id); $this->assertEquals('Test value updated', $customfieldsdata->testfield1); } public function test_cohort_update_cohort_event(): void { global $DB; $this->resetAfterTest(); // Setup the cohort data structure. $cohort = new \stdClass(); $cohort->contextid = \context_system::instance()->id; $cohort->name = 'test cohort'; $cohort->idnumber = 'testid'; $cohort->description = 'test cohort desc'; $cohort->descriptionformat = FORMAT_HTML; $cohort->theme = ''; $id = cohort_add_cohort($cohort); $this->assertNotEmpty($id); $cohort->name = 'test cohort 2'; // Catch Events. $sink = $this->redirectEvents(); // Peform the update. cohort_update_cohort($cohort); // Add again theme property to the cohort object for comparing it to the event snapshop. $cohort->theme = ''; $events = $sink->get_events(); $sink->close(); // Validate the event. $this->assertCount(1, $events); $event = $events[0]; $updatedcohort = $DB->get_record('cohort', array('id'=>$id)); $this->assertInstanceOf('\core\event\cohort_updated', $event); $this->assertEquals('cohort', $event->objecttable); $this->assertEquals($updatedcohort->id, $event->objectid); $this->assertEquals($updatedcohort->contextid, $event->contextid); $url = new \moodle_url('/cohort/edit.php', array('id' => $event->objectid)); $this->assertEquals($url, $event->get_url()); $this->assertEquals($cohort, $event->get_record_snapshot('cohort', $id)); $this->assertEventContextNotUsed($event); } public function test_cohort_delete_cohort(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $field = $this->create_cohort_custom_field(); $cohort = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']); $this->assertTrue($DB->record_exists('customfield_data', ['instanceid' => $cohort->id, 'fieldid' => $field->get('id')])); cohort_delete_cohort($cohort); $this->assertFalse($DB->record_exists('cohort', array('id'=>$cohort->id))); $this->assertFalse($DB->record_exists('customfield_data', ['instanceid' => $cohort->id, 'fieldid' => $field->get('id')])); } public function test_cohort_delete_cohort_event(): void { $this->resetAfterTest(); $cohort = $this->getDataGenerator()->create_cohort(); // Capture the events. $sink = $this->redirectEvents(); // Perform the delete. cohort_delete_cohort($cohort); $events = $sink->get_events(); $sink->close(); // Validate the event structure. $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\core\event\cohort_deleted', $event); $this->assertEquals('cohort', $event->objecttable); $this->assertEquals($cohort->id, $event->objectid); $url = new \moodle_url('/cohort/index.php', array('contextid' => $event->contextid)); $this->assertEquals($url, $event->get_url()); $this->assertEquals($cohort, $event->get_record_snapshot('cohort', $cohort->id)); $this->assertEventContextNotUsed($event); } public function test_cohort_delete_category(): void { global $DB; $this->resetAfterTest(); $category = $this->getDataGenerator()->create_category(); $cohort = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category->id)->id)); cohort_delete_category($category); $this->assertTrue($DB->record_exists('cohort', array('id'=>$cohort->id))); $newcohort = $DB->get_record('cohort', array('id'=>$cohort->id)); $this->assertEquals(\context_system::instance()->id, $newcohort->contextid); } public function test_cohort_add_member(): void { global $DB; $this->resetAfterTest(); $cohort = $this->getDataGenerator()->create_cohort(); $user = $this->getDataGenerator()->create_user(); $this->assertFalse($DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))); cohort_add_member($cohort->id, $user->id); $this->assertTrue($DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))); } public function test_cohort_add_member_event(): void { global $USER; $this->resetAfterTest(); // Setup the data. $cohort = $this->getDataGenerator()->create_cohort(); $user = $this->getDataGenerator()->create_user(); // Capture the events. $sink = $this->redirectEvents(); // Peform the add member operation. cohort_add_member($cohort->id, $user->id); $events = $sink->get_events(); $sink->close(); // Validate the event. $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\core\event\cohort_member_added', $event); $this->assertEquals('cohort', $event->objecttable); $this->assertEquals($cohort->id, $event->objectid); $this->assertEquals($user->id, $event->relateduserid); $this->assertEquals($USER->id, $event->userid); $url = new \moodle_url('/cohort/assign.php', array('id' => $event->objectid)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } public function test_cohort_remove_member(): void { global $DB; $this->resetAfterTest(); $cohort = $this->getDataGenerator()->create_cohort(); $user = $this->getDataGenerator()->create_user(); cohort_add_member($cohort->id, $user->id); $this->assertTrue($DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))); cohort_remove_member($cohort->id, $user->id); $this->assertFalse($DB->record_exists('cohort_members', array('cohortid'=>$cohort->id, 'userid'=>$user->id))); } public function test_cohort_remove_member_event(): void { global $USER; $this->resetAfterTest(); // Setup the data. $cohort = $this->getDataGenerator()->create_cohort(); $user = $this->getDataGenerator()->create_user(); cohort_add_member($cohort->id, $user->id); // Capture the events. $sink = $this->redirectEvents(); // Peform the remove operation. cohort_remove_member($cohort->id, $user->id); $events = $sink->get_events(); $sink->close(); // Validate the event. $this->assertCount(1, $events); $event = $events[0]; $this->assertInstanceOf('\core\event\cohort_member_removed', $event); $this->assertEquals('cohort', $event->objecttable); $this->assertEquals($cohort->id, $event->objectid); $this->assertEquals($user->id, $event->relateduserid); $this->assertEquals($USER->id, $event->userid); $url = new \moodle_url('/cohort/assign.php', array('id' => $event->objectid)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } public function test_cohort_is_member(): void { global $DB; $this->resetAfterTest(); $cohort = $this->getDataGenerator()->create_cohort(); $user = $this->getDataGenerator()->create_user(); $this->assertFalse(cohort_is_member($cohort->id, $user->id)); cohort_add_member($cohort->id, $user->id); $this->assertTrue(cohort_is_member($cohort->id, $user->id)); } public function test_cohort_get_cohorts(): void { global $DB; $this->resetAfterTest(); $category1 = $this->getDataGenerator()->create_category(); $category2 = $this->getDataGenerator()->create_category(); $cohort1 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category1->id)->id, 'name'=>'aaagrrryyy', 'idnumber'=>'','description'=>'')); $cohort2 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category1->id)->id, 'name'=>'bbb', 'idnumber'=>'', 'description'=>'yyybrrr')); $cohort3 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category1->id)->id, 'name'=>'ccc', 'idnumber'=>'xxarrrghyyy', 'description'=>'po_us')); $cohort4 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_system::instance()->id)); $result = cohort_get_cohorts(\context_coursecat::instance($category2->id)->id); $this->assertEquals(0, $result['totalcohorts']); $this->assertEquals(0, count($result['cohorts'])); $this->assertEquals(0, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id); $this->assertEquals(3, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1, $cohort2->id=>$cohort2, $cohort3->id=>$cohort3), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 0, 100, 'arrrgh'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort3->id=>$cohort3), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 0, 100, 'brrr'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort2->id=>$cohort2), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 0, 100, 'grrr'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 1, 1, 'yyy'); $this->assertEquals(3, $result['totalcohorts']); $this->assertEquals(array($cohort2->id=>$cohort2), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 0, 100, 'po_us'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort3->id=>$cohort3), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 0, 100, 'pokus'); $this->assertEquals(0, $result['totalcohorts']); $this->assertEquals(array(), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_system::instance()->id); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort4->id=>$cohort4), $result['cohorts']); $this->assertEquals(1, $result['allcohorts']); } public function test_cohort_get_all_cohorts(): void { global $DB; $this->resetAfterTest(); $category1 = $this->getDataGenerator()->create_category(); $category2 = $this->getDataGenerator()->create_category(); $cohort1 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category1->id)->id, 'name'=>'aaagrrryyy', 'idnumber'=>'','description'=>'')); $cohort2 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category1->id)->id, 'name'=>'bbb', 'idnumber'=>'', 'description'=>'yyybrrr')); $cohort3 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_coursecat::instance($category2->id)->id, 'name'=>'ccc', 'idnumber'=>'xxarrrghyyy', 'description'=>'po_us')); $cohort4 = $this->getDataGenerator()->create_cohort(array('contextid'=>\context_system::instance()->id)); // Get list of all cohorts as admin. $this->setAdminUser(); $result = cohort_get_all_cohorts(0, 100, ''); $this->assertEquals(4, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1, $cohort2->id=>$cohort2, $cohort3->id=>$cohort3, $cohort4->id=>$cohort4), $result['cohorts']); $this->assertEquals(4, $result['allcohorts']); $result = cohort_get_all_cohorts(0, 100, 'grrr'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1), $result['cohorts']); $this->assertEquals(4, $result['allcohorts']); // Get list of all cohorts as manager who has capability everywhere. $user = $this->getDataGenerator()->create_user(); $managerrole = $DB->get_record('role', array('shortname' => 'manager')); role_assign($managerrole->id, $user->id, \context_system::instance()->id); $this->setUser($user); $result = cohort_get_all_cohorts(0, 100, ''); $this->assertEquals(4, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1, $cohort2->id=>$cohort2, $cohort3->id=>$cohort3, $cohort4->id=>$cohort4), $result['cohorts']); $this->assertEquals(4, $result['allcohorts']); $result = cohort_get_all_cohorts(0, 100, 'grrr'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1), $result['cohorts']); $this->assertEquals(4, $result['allcohorts']); // Get list of all cohorts as manager who has capability everywhere except category2. $context2 = \context_coursecat::instance($category2->id); role_change_permission($managerrole->id, $context2, 'moodle/cohort:view', CAP_PROHIBIT); role_change_permission($managerrole->id, $context2, 'moodle/cohort:manage', CAP_PROHIBIT); $this->assertFalse(has_any_capability(array('moodle/cohort:view', 'moodle/cohort:manage'), $context2)); $result = cohort_get_all_cohorts(0, 100, ''); $this->assertEquals(3, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1, $cohort2->id=>$cohort2, $cohort4->id=>$cohort4), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_all_cohorts(0, 100, 'grrr'); $this->assertEquals(1, $result['totalcohorts']); $this->assertEquals(array($cohort1->id=>$cohort1), $result['cohorts']); $this->assertEquals(3, $result['allcohorts']); $result = cohort_get_cohorts(\context_coursecat::instance($category1->id)->id, 1, 1, 'yyy'); $this->assertEquals(2, $result['totalcohorts']); $this->assertEquals(array($cohort2->id=>$cohort2), $result['cohorts']); $this->assertEquals(2, $result['allcohorts']); } public function test_cohort_get_available_cohorts(): void { global $DB; $this->resetAfterTest(); $category1 = $this->getDataGenerator()->create_category(); $category2 = $this->getDataGenerator()->create_category(); $course1 = $this->getDataGenerator()->create_course(array('category' => $category1->id)); $course2 = $this->getDataGenerator()->create_course(array('category' => $category2->id)); $category1ctx = \context_coursecat::instance($category1->id); $category2ctx = \context_coursecat::instance($category2->id); $course1ctx = \context_course::instance(($course1->id)); $course2ctx = \context_course::instance(($course2->id)); $systemctx = \context_system::instance(); $cohort1 = $this->getDataGenerator()->create_cohort(array('contextid'=>$category1ctx->id, 'name'=>'aaagrrryyy', 'idnumber'=>'','description'=>'')); $cohort2 = $this->getDataGenerator()->create_cohort(array('contextid'=>$category1ctx->id, 'name'=>'bbb', 'idnumber'=>'', 'description'=>'yyybrrr', 'visible'=>0)); $cohort3 = $this->getDataGenerator()->create_cohort(array('contextid'=>$category2ctx->id, 'name'=>'ccc', 'idnumber'=>'xxarrrghyyy', 'description'=>'po_us')); $cohort4 = $this->getDataGenerator()->create_cohort(array('contextid'=>$systemctx->id, 'name' => 'ddd')); $cohort5 = $this->getDataGenerator()->create_cohort(array('contextid'=>$systemctx->id, 'visible'=>0, 'name' => 'eee')); /* Structure of generated course categories, courses and cohort: system -cohort4 (visible, has 3 members) -cohort5 (not visible, no members) category1 -cohort1 (visible, no members) -cohort2 (not visible, has 1 member) course1 category2 -cohort3 (visible, has 2 member) course2 In this test we call cohort_get_available_cohorts() for users with different roles and with different paramteres ($withmembers, $search, $offset, $limit) to make sure we go through all possible options of SQL query. */ // Admin can see visible and invisible cohorts defined in above contexts. $this->setAdminUser(); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 0, ''); $this->assertEquals(array($cohort1->id, $cohort2->id, $cohort4->id, $cohort5->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 2, ''); $this->assertEquals(array($cohort1->id, $cohort2->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 1, 2, ''); $this->assertEquals(array($cohort2->id, $cohort4->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 100, 'yyy'); $this->assertEquals(array($cohort1->id, $cohort2->id), array_keys($result)); $result = cohort_get_available_cohorts($course2ctx, COHORT_ALL, 0, 0, ''); $this->assertEquals(array($cohort3->id, $cohort4->id, $cohort5->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY); $this->assertEmpty($result); $result = cohort_get_available_cohorts($course2ctx, COHORT_WITH_MEMBERS_ONLY); $this->assertEmpty($result); // Get list of available cohorts as a teacher in the course. $user1 = $this->getDataGenerator()->create_user(); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); role_assign($teacherrole->id, $user1->id, $course1ctx->id); role_assign($teacherrole->id, $user1->id, $course2ctx->id); $this->setUser($user1); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 0, ''); $this->assertEquals(array($cohort1->id, $cohort4->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 1, ''); $this->assertEquals(array($cohort1->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 1, 1, ''); $this->assertEquals(array($cohort4->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 100, 'yyy'); $this->assertEquals(array($cohort1->id), array_keys($result)); $result = cohort_get_available_cohorts($course2ctx, COHORT_ALL, 0, 0, ''); $this->assertEquals(array($cohort3->id, $cohort4->id), array_keys($result)); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY); $this->assertEmpty($result); // Now add members to cohorts. $user2 = $this->getDataGenerator()->create_user(); $user3 = $this->getDataGenerator()->create_user(); $user4 = $this->getDataGenerator()->create_user(); $user5 = $this->getDataGenerator()->create_user(); $user6 = $this->getDataGenerator()->create_user(); cohort_add_member($cohort2->id, $user3->id); cohort_add_member($cohort3->id, $user2->id); cohort_add_member($cohort3->id, $user3->id); cohort_add_member($cohort4->id, $user4->id); cohort_add_member($cohort4->id, $user5->id); cohort_add_member($cohort4->id, $user6->id); // Check filtering non-empty cohorts as admin. $this->setAdminUser(); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort2->id, $cohort4->id), array_keys($result)); $this->assertEquals(1, $result[$cohort2->id]->memberscnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course2ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort3->id, $cohort4->id), array_keys($result)); $this->assertEquals(2, $result[$cohort3->id]->memberscnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, 'yyy'); $this->assertEquals(array($cohort2->id), array_keys($result)); $this->assertEquals(1, $result[$cohort2->id]->memberscnt); // Check filtering non-empty cohorts as teacher. $this->setUser($user1); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort4->id), array_keys($result)); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course2ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort3->id, $cohort4->id), array_keys($result)); $this->assertEquals(2, $result[$cohort3->id]->memberscnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_MEMBERS_ONLY, 0, 0, 'yyy'); $this->assertEmpty($result); // Enrol users. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($user2->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user3->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user5->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user6->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user3->id, $course2->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user4->id, $course2->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user5->id, $course2->id, $studentrole->id); $this->getDataGenerator()->enrol_user($user6->id, $course2->id, $studentrole->id); // Check cohorts with enrolments as admin. $this->setAdminUser(); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_ENROLLED_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort2->id, $cohort4->id), array_keys($result)); $this->assertEquals(1, $result[$cohort2->id]->enrolledcnt); $this->assertEquals(2, $result[$cohort4->id]->enrolledcnt); $this->assertEquals(1, $result[$cohort2->id]->memberscnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course2ctx, COHORT_WITH_ENROLLED_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort3->id, $cohort4->id), array_keys($result)); $this->assertEquals(1, $result[$cohort3->id]->enrolledcnt); $this->assertEquals(3, $result[$cohort4->id]->enrolledcnt); $this->assertEquals(2, $result[$cohort3->id]->memberscnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_ENROLLED_MEMBERS_ONLY, 0, 0, 'yyy'); $this->assertEquals(array($cohort2->id), array_keys($result)); $this->assertEquals(1, $result[$cohort2->id]->enrolledcnt); $this->assertEquals(1, $result[$cohort2->id]->memberscnt); $result = cohort_get_available_cohorts($course1ctx, COHORT_WITH_NOTENROLLED_MEMBERS_ONLY, 0, 0, ''); $this->assertEquals(array($cohort4->id), array_keys($result)); $this->assertEquals(2, $result[$cohort4->id]->enrolledcnt); $this->assertEquals(3, $result[$cohort4->id]->memberscnt); // Assign user1 additional 'manager' role in the category context. He can now see hidden cohort in category1 // but still can not see hidden category in system. $managerrole = $DB->get_record('role', array('shortname' => 'manager')); role_assign($managerrole->id, $user1->id, \context_coursecat::instance($category1->id)); $this->setUser($user1); $result = cohort_get_available_cohorts($course1ctx, COHORT_ALL, 0, 0, ''); $this->assertEquals(array($cohort1->id, $cohort2->id, $cohort4->id), array_keys($result)); } /** * Test that all get functions return custom fields data. * * @covers ::cohort_get_cohort * @covers ::cohort_get_cohorts * @covers ::cohort_get_all_cohorts * @covers ::cohort_get_available_cohorts * @covers ::cohort_get_user_cohorts */ public function test_get_functions_return_custom_fields(): void { $this->resetAfterTest(); $this->setAdminUser(); $user = self::getDataGenerator()->create_user(); $course = self::getDataGenerator()->create_course(); $coursectx = \context_course::instance(($course->id)); $this->create_cohort_custom_field(); $cohort1 = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']); $cohort2 = $this->getDataGenerator()->create_cohort(); // Test cohort_get_cohort. $result = cohort_get_cohort($cohort1->id, $coursectx, true); $this->assertObjectHasProperty('customfields', $result); $this->assertCount(1, $result->customfields); $field = reset($result->customfields); $this->assertInstanceOf(data_controller::class, $field); $this->assertEquals('testfield1', $field->get_field()->get('shortname')); $this->assertEquals('Test value 1', $field->get_value()); // Test custom fields are not returned if not needed. $result = cohort_get_cohort($cohort1->id, $coursectx); $this->assertObjectNotHasProperty('customfields', $result); // Test cohort_get_cohorts. $result = cohort_get_cohorts(\context_system::instance()->id, 0, 25, '', true); $this->assertEquals(2, $result['totalcohorts']); $this->assertEquals(2, $result['allcohorts']); foreach ($result['cohorts'] as $cohort) { $this->assertObjectHasProperty('customfields', $cohort); $this->assertCount(1, $cohort->customfields); $field = reset($cohort->customfields); $this->assertInstanceOf(data_controller::class, $field); $this->assertEquals('testfield1', $field->get_field()->get('shortname')); if ($cohort->id == $cohort1->id ) { $this->assertEquals('Test value 1', $field->get_value()); } else { $this->assertEquals('', $field->get_value()); } } // Test custom fields are not returned if not needed. $result = cohort_get_cohorts(\context_system::instance()->id, 0, 25, ''); $this->assertEquals(2, $result['totalcohorts']); $this->assertEquals(2, $result['allcohorts']); foreach ($result['cohorts'] as $cohort) { $this->assertObjectNotHasProperty('customfields', $cohort); } // Test test_cohort_get_all_cohorts. $result = cohort_get_all_cohorts(0, 100, '', true); $this->assertEquals(2, $result['totalcohorts']); $this->assertEquals(2, $result['allcohorts']); foreach ($result['cohorts'] as $cohort) { $this->assertObjectHasProperty('customfields', $cohort); $this->assertCount(1, $cohort->customfields); $field = reset($cohort->customfields); $this->assertInstanceOf(data_controller::class, $field); $this->assertEquals('testfield1', $field->get_field()->get('shortname')); if ($cohort->id == $cohort1->id ) { $this->assertEquals('Test value 1', $field->get_value()); } else { $this->assertEquals('', $field->get_value()); } } // Test custom fields are not returned if not needed. $result = cohort_get_all_cohorts(0, 100, ''); $this->assertEquals(2, $result['totalcohorts']); $this->assertEquals(2, $result['allcohorts']); foreach ($result['cohorts'] as $cohort) { $this->assertObjectNotHasProperty('customfields', $cohort); } // Test cohort_get_available_cohorts. $result = cohort_get_available_cohorts($coursectx, COHORT_ALL, 0, 25, '', true); $this->assertCount(2, $result); foreach ($result as $cohort) { $this->assertObjectHasProperty('customfields', $cohort); $this->assertCount(1, $cohort->customfields); $field = reset($cohort->customfields); $this->assertInstanceOf(data_controller::class, $field); $this->assertEquals('testfield1', $field->get_field()->get('shortname')); if ($cohort->id == $cohort1->id ) { $this->assertEquals('Test value 1', $field->get_value()); } else { $this->assertEquals('', $field->get_value()); } } // Test custom fields are not returned if not needed. $result = cohort_get_available_cohorts($coursectx, COHORT_ALL, 0, 25, ''); $this->assertCount(2, $result); foreach ($result as $cohort) { $this->assertObjectNotHasProperty('customfields', $cohort); } // Test cohort_get_user_cohorts. cohort_add_member($cohort1->id, $user->id); cohort_add_member($cohort2->id, $user->id); $result = cohort_get_user_cohorts($user->id, true); $this->assertCount(2, $result); foreach ($result as $cohort) { $this->assertObjectHasProperty('customfields', $cohort); $this->assertCount(1, $cohort->customfields); $field = reset($cohort->customfields); $this->assertInstanceOf(data_controller::class, $field); $this->assertEquals('testfield1', $field->get_field()->get('shortname')); if ($cohort->id == $cohort1->id ) { $this->assertEquals('Test value 1', $field->get_value()); } else { $this->assertEquals('', $field->get_value()); } } // Test that there is no custom fields returned if not required. $result = cohort_get_user_cohorts($user->id); $this->assertCount(2, $result); foreach ($result as $cohort) { $this->assertObjectNotHasProperty('customfields', $cohort); } } /** * Create a cohort with allowcohortthemes enabled/disabled. */ public function test_cohort_add_theme_cohort(): void { global $DB; $this->resetAfterTest(); // Theme is added when allowcohortthemes is enabled. set_config('allowcohortthemes', 1); set_config('theme', 'boost'); $systemctx = \context_system::instance(); $cohort1 = $this->getDataGenerator()->create_cohort(array('contextid' => $systemctx->id, 'name' => 'test cohort 1', 'idnumber' => 'testid1', 'description' => 'test cohort desc', 'descriptionformat' => FORMAT_HTML, 'theme' => 'classic')); $id = cohort_add_cohort($cohort1); $this->assertNotEmpty($id); $newcohort = $DB->get_record('cohort', array('id' => $id)); $this->assertEquals($cohort1->contextid, $newcohort->contextid); $this->assertSame($cohort1->name, $newcohort->name); $this->assertSame($cohort1->description, $newcohort->description); $this->assertEquals($cohort1->descriptionformat, $newcohort->descriptionformat); $this->assertNotEmpty($newcohort->theme); $this->assertSame($cohort1->theme, $newcohort->theme); $this->assertNotEmpty($newcohort->timecreated); $this->assertSame($newcohort->component, ''); $this->assertSame($newcohort->timecreated, $newcohort->timemodified); // Theme is not added when allowcohortthemes is disabled. set_config('allowcohortthemes', 0); $cohort2 = $this->getDataGenerator()->create_cohort(array('contextid' => $systemctx->id, 'name' => 'test cohort 2', 'idnumber' => 'testid2', 'description' => 'test cohort desc', 'descriptionformat' => FORMAT_HTML, 'theme' => 'classic')); $id = cohort_add_cohort($cohort2); $this->assertNotEmpty($id); $newcohort = $DB->get_record('cohort', array('id' => $id)); $this->assertSame($cohort2->name, $newcohort->name); $this->assertEmpty($newcohort->theme); } /** * Update a cohort with allowcohortthemes enabled/disabled. */ public function test_cohort_update_theme_cohort(): void { global $DB; $this->resetAfterTest(); // Enable cohort themes. set_config('allowcohortthemes', 1); set_config('theme', 'boost'); $systemctx = \context_system::instance(); $cohort1 = $this->getDataGenerator()->create_cohort(array('contextid' => $systemctx->id, 'name' => 'test cohort 1', 'idnumber' => 'testid1', 'description' => 'test cohort desc', 'descriptionformat' => FORMAT_HTML, 'theme' => 'classic')); $id = cohort_add_cohort($cohort1); $this->assertNotEmpty($id); // Theme is updated when allowcohortthemes is enabled. $cohort1 = $DB->get_record('cohort', array('id' => $id)); $cohort1->name = 'test cohort 1 updated'; $cohort1->theme = 'classic'; cohort_update_cohort($cohort1); $updatedcohort = $DB->get_record('cohort', array('id' => $id)); $this->assertEquals($cohort1->contextid, $updatedcohort->contextid); $this->assertSame($cohort1->name, $updatedcohort->name); $this->assertSame($cohort1->description, $updatedcohort->description); $this->assertNotEmpty($updatedcohort->theme); $this->assertSame($cohort1->theme, $updatedcohort->theme); // Theme is not updated neither overwritten when allowcohortthemes is disabled. set_config('allowcohortthemes', 0); $cohort2 = $DB->get_record('cohort', array('id' => $id)); $cohort2->theme = 'classic'; cohort_update_cohort($cohort2); $updatedcohort = $DB->get_record('cohort', array('id' => $id)); $this->assertEquals($cohort2->contextid, $updatedcohort->contextid); $this->assertNotEmpty($updatedcohort->theme); $this->assertSame($cohort1->theme, $updatedcohort->theme); } /** * Test that lib function returns custom field data for a cohorts. * * @covers ::cohort_get_custom_fields_data */ public function test_cohort_get_custom_fields_data(): void { $this->resetAfterTest(); $this->setAdminUser(); $this->create_cohort_custom_field(); $cohort1 = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']); $cohort2 = $this->getDataGenerator()->create_cohort(); $result = cohort_get_custom_fields_data([$cohort1->id, $cohort2->id, 777]); $this->assertArrayHasKey($cohort1->id, $result); $this->assertArrayHasKey($cohort2->id, $result); $this->assertArrayHasKey(777, $result); foreach ($result as $cohortid => $fieldcontrollers) { foreach ($fieldcontrollers as $fieldcontroller) { $this->assertInstanceOf(data_controller::class, $fieldcontroller); if ($cohortid == $cohort1->id) { $this->assertSame('Test value 1', $fieldcontroller->export_value()); } else { $this->assertNull($fieldcontroller->export_value()); } } } } /** * Test the behaviour of cohort_get_cohort(). * * @covers ::cohort_get_cohort */ public function test_cohort_get_cohort(): void { $this->resetAfterTest(); $cat = $this->getDataGenerator()->create_category(); $cat1 = $this->getDataGenerator()->create_category(['parent' => $cat->id]); $cat2 = $this->getDataGenerator()->create_category(['parent' => $cat->id]); $course1 = $this->getDataGenerator()->create_course(['category' => $cat1->id, 'shortname' => 'ANON1']); $course2 = $this->getDataGenerator()->create_course(['category' => $cat2->id, 'shortname' => 'ANON2']); $cohort1 = $this->getDataGenerator()->create_cohort(['contextid' => \context_coursecat::instance($cat1->id)->id]); $result = cohort_get_cohort($cohort1->id, \context_course::instance($course2->id)); $this->assertFalse($result); $result = cohort_get_cohort($cohort1->id, \context_course::instance($course2->id), true); $this->assertFalse($result); $result = cohort_get_cohort($cohort1->id, \context_course::instance($course1->id)); $this->assertEquals($cohort1->id, $result->id); $result = cohort_get_cohort($cohort1->id, \context_course::instance($course1->id), true); $this->assertEquals($cohort1->id, $result->id); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/grade/tests/lib_test.php000064400000133300152266572120023433 0ustar00. /** * Unit tests for grade/lib.php. * * @package core_grades * @category test * @copyright 2016 Jun Pataleta * @license http://www.gnu.org/copyleft/gpl.html GNU Public License */ namespace core_grades; use assign; use cm_info; use grade_item; use grade_plugin_return; use grade_report_grader; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/grade/lib.php'); /** * Unit tests for grade/lib.php. * * @package core_grades * @category test * @copyright 2016 Jun Pataleta * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { /** * Test can_output_item. */ public function test_can_output_item(): void { $this->resetAfterTest(); $generator = $this->getDataGenerator(); // Course level grade category. $course = $generator->create_course(); // Grade tree looks something like: // - Test course (Rendered). $gradetree = \grade_category::fetch_course_tree($course->id); $this->assertTrue(\grade_tree::can_output_item($gradetree)); // Add a grade category with default settings. $generator->create_grade_category(array('courseid' => $course->id)); // Grade tree now looks something like: // - Test course n (Rendered). // -- Grade category n (Rendered). $gradetree = \grade_category::fetch_course_tree($course->id); $this->assertNotEmpty($gradetree['children']); foreach ($gradetree['children'] as $child) { $this->assertTrue(\grade_tree::can_output_item($child)); } // Add a grade category with grade type = None. $nototalcategory = 'No total category'; $nototalparams = [ 'courseid' => $course->id, 'fullname' => $nototalcategory, 'aggregation' => GRADE_AGGREGATE_WEIGHTED_MEAN ]; $nototal = $generator->create_grade_category($nototalparams); $catnototal = \grade_category::fetch(array('id' => $nototal->id)); // Set the grade type of the grade item associated to the grade category. $catitemnototal = $catnototal->load_grade_item(); $catitemnototal->gradetype = GRADE_TYPE_NONE; $catitemnototal->update(); // Grade tree looks something like: // - Test course n (Rendered). // -- Grade category n (Rendered). // -- No total category (Not rendered). $gradetree = \grade_category::fetch_course_tree($course->id); foreach ($gradetree['children'] as $child) { if ($child['object']->fullname == $nototalcategory) { $this->assertFalse(\grade_tree::can_output_item($child)); } else { $this->assertTrue(\grade_tree::can_output_item($child)); } } // Add another grade category with default settings under 'No total category'. $normalinnototalparams = [ 'courseid' => $course->id, 'fullname' => 'Normal category in no total category', 'parent' => $nototal->id ]; $generator->create_grade_category($normalinnototalparams); // Grade tree looks something like: // - Test course n (Rendered). // -- Grade category n (Rendered). // -- No total category (Rendered). // --- Normal category in no total category (Rendered). $gradetree = \grade_category::fetch_course_tree($course->id); foreach ($gradetree['children'] as $child) { // All children are now visible. $this->assertTrue(\grade_tree::can_output_item($child)); if (!empty($child['children'])) { foreach ($child['children'] as $grandchild) { $this->assertTrue(\grade_tree::can_output_item($grandchild)); } } } // Add a grade category with grade type = None. $nototalcategory2 = 'No total category 2'; $nototal2params = [ 'courseid' => $course->id, 'fullname' => $nototalcategory2, 'aggregation' => GRADE_AGGREGATE_WEIGHTED_MEAN ]; $nototal2 = $generator->create_grade_category($nototal2params); $catnototal2 = \grade_category::fetch(array('id' => $nototal2->id)); // Set the grade type of the grade item associated to the grade category. $catitemnototal2 = $catnototal2->load_grade_item(); $catitemnototal2->gradetype = GRADE_TYPE_NONE; $catitemnototal2->update(); // Add a category with no total under 'No total category'. $nototalinnototalcategory = 'Category with no total in no total category'; $nototalinnototalparams = [ 'courseid' => $course->id, 'fullname' => $nototalinnototalcategory, 'aggregation' => GRADE_AGGREGATE_WEIGHTED_MEAN, 'parent' => $nototal2->id ]; $nototalinnototal = $generator->create_grade_category($nototalinnototalparams); $catnototalinnototal = \grade_category::fetch(array('id' => $nototalinnototal->id)); // Set the grade type of the grade item associated to the grade category. $catitemnototalinnototal = $catnototalinnototal->load_grade_item(); $catitemnototalinnototal->gradetype = GRADE_TYPE_NONE; $catitemnototalinnototal->update(); // Grade tree looks something like: // - Test course n (Rendered). // -- Grade category n (Rendered). // -- No total category (Rendered). // --- Normal category in no total category (Rendered). // -- No total category 2 (Not rendered). // --- Category with no total in no total category (Not rendered). $gradetree = \grade_category::fetch_course_tree($course->id); foreach ($gradetree['children'] as $child) { if ($child['object']->fullname == $nototalcategory2) { $this->assertFalse(\grade_tree::can_output_item($child)); } else { $this->assertTrue(\grade_tree::can_output_item($child)); } if (!empty($child['children'])) { foreach ($child['children'] as $grandchild) { if ($grandchild['object']->fullname == $nototalinnototalcategory) { $this->assertFalse(\grade_tree::can_output_item($grandchild)); } else { $this->assertTrue(\grade_tree::can_output_item($grandchild)); } } } } } /** * Tests that ungraded_counts calculates count and sum of grades correctly when there are graded users. * * @covers \grade_report::ungraded_counts */ public function test_ungraded_counts_count_sumgrades(): void { global $DB; $this->resetAfterTest(true); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher'], '*', MUST_EXIST); // Custom roles (gradable and non gradable). $gradeblerole = create_role('New student role', 'gradable', 'Gradable role', 'student'); $nongradeblerole = create_role('New student role', 'nongradable', 'Non gradable role', 'student'); // Set up gradable roles. set_config('gradebookroles', $studentrole->id . ',' . $gradeblerole); // Create users. // These will be gradable users. $student1 = $this->getDataGenerator()->create_user(['username' => 'student1']); $student2 = $this->getDataGenerator()->create_user(['username' => 'student2']); $student3 = $this->getDataGenerator()->create_user(['username' => 'student3']); $student5 = $this->getDataGenerator()->create_user(['username' => 'student5']); // These will be non-gradable users. $student4 = $this->getDataGenerator()->create_user(['username' => 'student4']); $student6 = $this->getDataGenerator()->create_user(['username' => 'student6']); $teacher = $this->getDataGenerator()->create_user(['username' => 'teacher']); // Enrol students. $this->getDataGenerator()->enrol_user($student1->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student2->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student3->id, $course1->id, $gradeblerole); $this->getDataGenerator()->enrol_user($student5->id, $course1->id, $nongradeblerole); $this->getDataGenerator()->enrol_user($student6->id, $course1->id, $studentrole->id); $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id); // User that is enrolled in a different course. $this->getDataGenerator()->enrol_user($student4->id, $course2->id, $studentrole->id); // Mark user as deleted. $student6->deleted = 1; $DB->update_record('user', $student6); // Create grade items in course 1. $assign1 = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]); $assign2 = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]); $quiz1 = $this->getDataGenerator()->create_module('quiz', ['course' => $course1->id]); $manuaitem = new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course1->id, ])); // Create grade items in course 2. $assign3 = $this->getDataGenerator()->create_module('assign', ['course' => $course2->id]); // Grade users in first course. $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign1->id)); $assigninstance = new assign($cm->context, $cm, $course1); $grade = $assigninstance->get_user_grade($student1->id, true); $grade->grade = 40; $assigninstance->update_grade($grade); $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign2->id)); $assigninstance = new assign($cm->context, $cm, $course1); $grade = $assigninstance->get_user_grade($student3->id, true); $grade->grade = 50; $assigninstance->update_grade($grade); // Override grade for assignment in gradebook. $gi = \grade_item::fetch([ 'itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $cm->instance, 'courseid' => $course1->id ]); $gi->update_final_grade($student3->id, 55); // Grade user in second course. $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign3->id)); $assigninstance = new assign($cm->context, $cm, $course2); $grade = $assigninstance->get_user_grade($student4->id, true); $grade->grade = 40; $assigninstance->update_grade($grade); $manuaitem->update_final_grade($student1->id, 1); $manuaitem->update_final_grade($student3->id, 2); // Trigger a regrade. grade_force_full_regrading($course1->id); grade_force_full_regrading($course2->id); grade_regrade_final_grades($course1->id); grade_regrade_final_grades($course2->id); // Initialise reports. $context1 = \context_course::instance($course1->id); $context2 = \context_course::instance($course2->id); $gpr1 = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course1, ] ); $gpr2 = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course2, ] ); $report1 = new grade_report_grader($course1->id, $gpr1, $context1); $report2 = new grade_report_grader($course2->id, $gpr2, $context2); $ungradedcounts = []; $ungradedcounts[$course1->id] = $report1->ungraded_counts(false); $ungradedcounts[$course2->id] = $report2->ungraded_counts(false); foreach ($ungradedcounts as $key => $ungradedcount) { $gradeitems = grade_item::fetch_all(['courseid' => $key]); if ($key == $course1->id) { $gradeitemkeys = array_keys($gradeitems); $ungradedcountskeys = array_keys($ungradedcount['ungradedcounts']); // For each grade item there is some student that is not graded yet in course 1. $this->assertEmpty(array_diff_key($gradeitemkeys, $ungradedcountskeys)); // Only quiz does not have any grades, the remaning 4 grade items should have some. // We can do more and match by gradeitem id numbers. But feels like overengeneering. $this->assertEquals(4, count($ungradedcount['sumarray'])); } else { // In course 2 there is one student, and he is graded. $this->assertEmpty($ungradedcount['ungradedcounts']); // There are 2 grade items and they both have some grades. $this->assertEquals(2, count($ungradedcount['sumarray'])); } foreach ($gradeitems as $gradeitem) { $sumgrades = null; if (array_key_exists($gradeitem->id, $ungradedcount['ungradedcounts'])) { $ungradeditem = $ungradedcount['ungradedcounts'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { $this->assertEquals(1, $ungradeditem->count); } else if ($gradeitem->itemmodule === 'assign') { $this->assertEquals(2, $ungradeditem->count); } else if ($gradeitem->itemmodule === 'quiz') { $this->assertEquals(3, $ungradeditem->count); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals(1, $ungradeditem->count); } } if (array_key_exists($gradeitem->id, $ungradedcount['sumarray'])) { $sumgrades = $ungradedcount['sumarray'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { if ($key == $course1->id) { $this->assertEquals('98.00000', $sumgrades); // 40 + 55 + 1 + 2 } else { $this->assertEquals('40.00000', $sumgrades); } } else if ($gradeitem->itemmodule === 'assign') { if (($gradeitem->itemname === $assign1->name) || ($gradeitem->itemname === $assign3->name)) { $this->assertEquals('40.00000', $sumgrades); } else { $this->assertEquals('55.00000', $sumgrades); } } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals('3.00000', $sumgrades); } } } } } /** * Tests that ungraded_counts calculates count and sum of grades correctly when there are hidden grades. * @dataProvider ungraded_counts_hidden_grades_data * @param bool $hidden Whether to inlcude hidden grades or not. * @param array $expectedcount expected count value (i.e. number of ugraded grades) * @param array $expectedsumarray expceted sum of grades * * @covers \grade_report::ungraded_counts */ public function test_ungraded_counts_hidden_grades(bool $hidden, array $expectedcount, array $expectedsumarray): void { $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); // Create users. $student1 = $this->getDataGenerator()->create_user(['username' => 'student1']); $student2 = $this->getDataGenerator()->create_user(['username' => 'student2']); $student3 = $this->getDataGenerator()->create_user(['username' => 'student3']); // Enrol students. $this->getDataGenerator()->enrol_user($student1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($student3->id, $course->id, 'student'); // Create grade items in course. $manuaitem = new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course->id, ])); // Grade users. $manuaitem->update_final_grade($student1->id, 1); $manuaitem->update_final_grade($student3->id, 2); // Create a hidden grade. $manuaitem->update_final_grade($student2->id, 3); $grade = \grade_grade::fetch(['itemid' => $manuaitem->id, 'userid' => $student2->id]); $grade->hidden = 1; $grade->update(); // Trigger a regrade. grade_force_full_regrading($course->id); grade_regrade_final_grades($course->id); // Initialise reports. $context = \context_course::instance($course->id); $gpr = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course, ] ); $report = new grade_report_grader($course->id, $gpr, $context); $ungradedcounts = $report->ungraded_counts(false, $hidden); $gradeitems = grade_item::fetch_all(['courseid' => $course->id]); foreach ($gradeitems as $gradeitem) { $sumgrades = null; if (array_key_exists($gradeitem->id, $ungradedcounts['ungradedcounts'])) { $ungradeditem = $ungradedcounts['ungradedcounts'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { $this->assertEquals($expectedcount['course'], $ungradeditem->count); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals($expectedcount['Grade item1'], $ungradeditem->count); } } if (array_key_exists($gradeitem->id, $ungradedcounts['sumarray'])) { $sumgrades = $ungradedcounts['sumarray'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { $this->assertEquals($expectedsumarray['course'], $sumgrades); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals($expectedsumarray['Grade item1'], $sumgrades); } } } } /** * Data provider for test_ungraded_counts_hidden_grades * * @return array of testing scenarios */ public static function ungraded_counts_hidden_grades_data(): array { return [ 'nohidden' => [ 'hidden' => false, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 6.00000, 'Grade item1' => 3.00000], ], 'includehidden' => [ 'hidden' => true, 'expectedcount' => ['course' => 1, 'Grade item1' => 2], 'expectedsumarray' => ['course' => 6.00000, 'Grade item1' => 6.00000], ], ]; } /** * Tests that ungraded_counts calculates count and sum of grades correctly for groups when there are graded users. * * @covers \grade_report::ungraded_counts */ public function test_ungraded_count_sumgrades_groups(): void { global $DB; $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); // Create users. $student1 = $this->getDataGenerator()->create_user(['username' => 'student1']); $student2 = $this->getDataGenerator()->create_user(['username' => 'student2']); $student3 = $this->getDataGenerator()->create_user(['username' => 'student3']); // Enrol students. $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student3->id, $course->id, $studentrole->id); $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); $this->getDataGenerator()->create_group_member(['userid' => $student1->id, 'groupid' => $group1->id]); $this->getDataGenerator()->create_group_member(['userid' => $student2->id, 'groupid' => $group2->id]); $this->getDataGenerator()->create_group_member(['userid' => $student3->id, 'groupid' => $group2->id]); $DB->set_field('course', 'groupmode', SEPARATEGROUPS, ['id' => $course->id]); // Create grade items. $assign1 = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]); $assign2 = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]); $quiz1 = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); $manuaitem = new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course->id, ])); // Grade users. $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign1->id)); $assigninstance = new assign($cm->context, $cm, $course); $grade = $assigninstance->get_user_grade($student1->id, true); $grade->grade = 40; $assigninstance->update_grade($grade); $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign2->id)); $assigninstance = new assign($cm->context, $cm, $course); $grade = $assigninstance->get_user_grade($student3->id, true); $grade->grade = 50; $assigninstance->update_grade($grade); $manuaitem->update_final_grade($student1->id, 1); $manuaitem->update_final_grade($student3->id, 2); // Trigger a regrade. grade_force_full_regrading($course->id); grade_regrade_final_grades($course->id); // Initialise report. $context = \context_course::instance($course->id); $gpr1 = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course, 'groupid' => $group1->id, ] ); $gpr2 = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course, 'groupid' => $group2->id, ] ); $report1 = new grade_report_grader($course->id, $gpr1, $context); $report2 = new grade_report_grader($course->id, $gpr2, $context); $ungradedcounts = []; $ungradedcounts[$group1->id] = $report1->ungraded_counts(true); $ungradedcounts[$group2->id] = $report2->ungraded_counts(true); $gradeitems = grade_item::fetch_all(['courseid' => $course->id]); // In group1 there is 1 student and assign1 and quiz1 are not graded for him. $this->assertEquals(2, count($ungradedcounts[$group1->id]['ungradedcounts'])); // In group1 manual grade item, assign1 and course total have some grades. $this->assertEquals(3, count($ungradedcounts[$group1->id]['sumarray'])); // In group2 student2 has no grades at all so all 5 grade items should present. $this->assertEquals(5, count($ungradedcounts[$group2->id]['ungradedcounts'])); // In group2 manual grade item, assign2 and course total have some grades. $this->assertEquals(3, count($ungradedcounts[$group2->id]['sumarray'])); foreach ($gradeitems as $gradeitem) { $sumgrades = null; foreach ($ungradedcounts as $key => $ungradedcount) { if (array_key_exists($gradeitem->id, $ungradedcount['ungradedcounts'])) { $ungradeditem = $ungradedcount['ungradedcounts'][$gradeitem->id]; if ($key == $group1->id) { // Both assign2 and quiz1 are not graded for student1. $this->assertEquals(1, $ungradeditem->count); } else { if ($gradeitem->itemtype === 'course') { $this->assertEquals(1, $ungradeditem->count); } else if ($gradeitem->itemmodule === 'assign') { if ($gradeitem->itemname === $assign1->name) { // In group2 assign1 is not graded for anyone. $this->assertEquals(2, $ungradeditem->count); } else { // In group2 assign2 is graded for student3. $this->assertEquals(1, $ungradeditem->count); } } else if ($gradeitem->itemmodule === 'quiz') { $this->assertEquals(2, $ungradeditem->count); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals(1, $ungradeditem->count); } } } if (array_key_exists($gradeitem->id, $ungradedcount['sumarray'])) { $sumgrades = $ungradedcount['sumarray'][$gradeitem->id]; if ($key == $group1->id) { if ($gradeitem->itemtype === 'course') { $this->assertEquals('41.00000', $sumgrades); } else if ($gradeitem->itemmodule === 'assign') { $this->assertEquals('40.00000', $sumgrades); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals('1.00000', $sumgrades); } } else { if ($gradeitem->itemtype === 'course') { $this->assertEquals('52.00000', $sumgrades); } else if ($gradeitem->itemmodule === 'assign') { $this->assertEquals('50.00000', $sumgrades); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals('2.00000', $sumgrades); } } } } } } /** * Tests that ungraded_counts calculates count and sum of grades correctly when there are hidden grades. * @dataProvider ungraded_counts_only_active_enrol_data * @param bool $onlyactive Site setting to show only active users. * @param int $hascapability Capability constant * @param bool|null $showonlyactiveenrolpref Show only active user preference. * @param array $expectedcount expected count value (i.e. number of ugraded grades) * @param array $expectedsumarray expected sum of grades * * @covers \grade_report::ungraded_counts */ public function test_ungraded_counts_only_active_enrol(bool $onlyactive, int $hascapability, ?bool $showonlyactiveenrolpref, array $expectedcount, array $expectedsumarray): void { global $CFG, $DB; $this->resetAfterTest(); $CFG->grade_report_showonlyactiveenrol = $onlyactive; $course = $this->getDataGenerator()->create_course(); // Create users. $student1 = $this->getDataGenerator()->create_user(['username' => 'student1']); $student2 = $this->getDataGenerator()->create_user(['username' => 'student2']); $student3 = $this->getDataGenerator()->create_user(['username' => 'student3']); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); // Enrol students. $this->getDataGenerator()->enrol_user($student1->id, $course->id, 'student'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student'); // Give teacher 'viewsuspendedusers' capability and set a preference to display suspended users. $roleteacher = $DB->get_record('role', ['shortname' => 'teacher'], '*', MUST_EXIST); $coursecontext = \context_course::instance($course->id); assign_capability('moodle/course:viewsuspendedusers', $hascapability, $roleteacher->id, $coursecontext, true); set_user_preference('grade_report_showonlyactiveenrol', $showonlyactiveenrolpref, $teacher); accesslib_clear_all_caches_for_unit_testing(); $this->setUser($teacher); // Suspended student. $this->getDataGenerator()->enrol_user($student3->id, $course->id, 'student', 'manual', 0, 0, ENROL_USER_SUSPENDED); // Create grade items in course. $manuaitem = new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course->id, ])); // Grade users. $manuaitem->update_final_grade($student1->id, 1); $manuaitem->update_final_grade($student3->id, 2); // Trigger a regrade. grade_force_full_regrading($course->id); grade_regrade_final_grades($course->id); // Initialise reports. $context = \context_course::instance($course->id); $gpr = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course, ] ); $report = new grade_report_grader($course->id, $gpr, $context); $showonlyactiveenrol = $report->show_only_active(); $ungradedcounts = $report->ungraded_counts(false, false, $showonlyactiveenrol); $gradeitems = grade_item::fetch_all(['courseid' => $course->id]); foreach ($gradeitems as $gradeitem) { $sumgrades = null; if (array_key_exists($gradeitem->id, $ungradedcounts['ungradedcounts'])) { $ungradeditem = $ungradedcounts['ungradedcounts'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { $this->assertEquals($expectedcount['course'], $ungradeditem->count); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals($expectedcount['Grade item1'], $ungradeditem->count); } } if (array_key_exists($gradeitem->id, $ungradedcounts['sumarray'])) { $sumgrades = $ungradedcounts['sumarray'][$gradeitem->id]; if ($gradeitem->itemtype === 'course') { $this->assertEquals($expectedsumarray['course'], $sumgrades); } else if ($gradeitem->itemtype === 'manual') { $this->assertEquals($expectedsumarray['Grade item1'], $sumgrades); } } } } /** * Data provider for test_ungraded_counts_hidden_grades * * @return array of testing scenarios */ public static function ungraded_counts_only_active_enrol_data(): array { return [ 'Show only active and no user preference' => [ 'onlyactive' => true, 'hascapability' => 1, 'showonlyactiveenrolpref' => null, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 1, 'Grade item1' => 1.00000], ], 'Show only active and user preference set to true' => [ 'onlyactive' => true, 'hascapability' => 1, 'showonlyactiveenrolpref' => true, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 1, 'Grade item1' => 1.00000], ], 'Show only active and user preference set to false' => [ 'onlyactive' => true, 'hascapability' => 1, 'showonlyactiveenrolpref' => false, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 3.00000, 'Grade item1' => 3.00000], ], 'Include suspended with capability and user preference set to true' => [ 'onlyactive' => false, 'hascapability' => 1, 'showonlyactiveenrolpref' => true, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 1.00000, 'Grade item1' => 1.00000], ], 'Include suspended with capability and user preference set to false' => [ 'onlyactive' => false, 'hascapability' => 1, 'showonlyactiveenrolpref' => false, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 3.00000, 'Grade item1' => 3.00000], ], 'Include suspended with capability and no user preference' => [ 'onlyactive' => false, 'hascapability' => 1, 'showonlyactiveenrolpref' => null, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 3.00000, 'Grade item1' => 3.00000], ], 'Include suspended without capability' => [ 'onlyactive' => false, 'hascapability' => -1, 'showonlyactiveenrolpref' => null, 'expectedcount' => ['course' => 1, 'Grade item1' => 1], 'expectedsumarray' => ['course' => 1.00000, 'Grade item1' => 1.00000], ], ]; } /** * Tests for calculate_average. * @dataProvider calculate_average_data * @param int $meanselection Whether to inlcude all grades or non-empty grades in aggregation. * @param array $expectedmeancount expected meancount value * @param array $expectedaverage expceted average value * * @covers \grade_report::calculate_average */ public function test_calculate_average(int $meanselection, array $expectedmeancount, array $expectedaverage): void { global $DB; $this->resetAfterTest(true); $course = $this->getDataGenerator()->create_course(); $student1 = $this->getDataGenerator()->create_user(['username' => 'student1']); $student2 = $this->getDataGenerator()->create_user(['username' => 'student2']); $student3 = $this->getDataGenerator()->create_user(['username' => 'student3']); $studentrole = $DB->get_record('role', ['shortname' => 'student'], '*', MUST_EXIST); // Enrol students. $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id); $this->getDataGenerator()->enrol_user($student3->id, $course->id, $studentrole->id); // Create activities. $assign1 = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]); $assign2 = $this->getDataGenerator()->create_module('assign', ['course' => $course->id]); $quiz1 = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); // Grade users. $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign1->id)); $assigninstance = new assign($cm->context, $cm, $course); $grade = $assigninstance->get_user_grade($student1->id, true); $grade->grade = 40; $assigninstance->update_grade($grade); $grade = $assigninstance->get_user_grade($student2->id, true); $grade->grade = 30; $assigninstance->update_grade($grade); $cm = cm_info::create(get_coursemodule_from_instance('assign', $assign2->id)); $assigninstance = new assign($cm->context, $cm, $course); $grade = $assigninstance->get_user_grade($student3->id, true); $grade->grade = 50; $assigninstance->update_grade($grade); $grade = $assigninstance->get_user_grade($student1->id, true); $grade->grade = 100; $assigninstance->update_grade($grade); // Make a manual grade items. $manuaitem = new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course->id, ])); $manuaitem->update_final_grade($student1->id, 1); $manuaitem->update_final_grade($student3->id, 2); // Initialise report. $context = \context_course::instance($course->id); $gpr = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course, ] ); $report = new grade_report_grader($course->id, $gpr, $context); $ungradedcounts = $report->ungraded_counts(false); $ungradedcounts['report']['meanselection'] = $meanselection; $gradeitems = grade_item::fetch_all(['courseid' => $course->id]); foreach ($gradeitems as $gradeitem) { $name = $gradeitem->itemname . ' ' . $gradeitem->itemtype; $aggr = $report->calculate_average($gradeitem, $ungradedcounts); $this->assertEquals($expectedmeancount[$name], $aggr['meancount']); $this->assertEquals($expectedaverage[$name], $aggr['average']); } } /** * Data provider for test_calculate_average * * @return array of testing scenarios */ public static function calculate_average_data(): array { return [ 'Non-empty grades' => [ 'meanselection' => 1, 'expectedmeancount' => [' course' => 3, 'Assignment 1 mod' => 2, 'Assignment 2 mod' => 2, 'Quiz 1 mod' => 0, 'Grade item1 manual' => 2], 'expectedaverage' => [' course' => 73.33333333333333, 'Assignment 1 mod' => 35.0, 'Assignment 2 mod' => 75.0, 'Quiz 1 mod' => null, 'Grade item1 manual' => 1.5], ], 'All grades' => [ 'meanselection' => 0, 'expectedmeancount' => [' course' => 3, 'Assignment 1 mod' => 3, 'Assignment 2 mod' => 3, 'Quiz 1 mod' => 3, 'Grade item1 manual' => 3], 'expectedaverage' => [' course' => 73.33333333333333, 'Assignment 1 mod' => 23.333333333333332, 'Assignment 2 mod' => 50.0, 'Quiz 1 mod' => null, 'Grade item1 manual' => 1.0], ], ]; } /** * Tests for item types. * * @covers \grade_report::item_types */ public function test_item_types(): void { $this->resetAfterTest(true); $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); // Create activities. $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]); $this->getDataGenerator()->create_module('assign', ['course' => $course1->id]); $this->getDataGenerator()->create_module('quiz', ['course' => $course1->id]); $this->getDataGenerator()->create_module('assign', ['course' => $course2->id]); // Create manual grade items. new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item1', 'idnumber' => 'git1', 'courseid' => $course1->id, ])); new \grade_item($this->getDataGenerator()->create_grade_item([ 'itemname' => 'Grade item2', 'idnumber' => 'git2', 'courseid' => $course2->id, ])); // Create a grade category (it should not be fetched by item_types). new \grade_category($this->getDataGenerator() ->create_grade_category(['courseid' => $course1->id]), false); // Initialise reports. $context = \context_course::instance($course1->id); $gpr = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course1, ] ); $report1 = new grade_report_grader($course1->id, $gpr, $context); $context = \context_course::instance($course2->id); $gpr = new grade_plugin_return( [ 'type' => 'report', 'plugin' => 'grader', 'course' => $course2, ] ); $report2 = new grade_report_grader($course2->id, $gpr, $context); $gradeitems1 = $report1->item_types(); $gradeitems2 = $report2->item_types(); $this->assertEquals(3, count($gradeitems1)); $this->assertEquals(2, count($gradeitems2)); $this->assertArrayHasKey('assign', $gradeitems1); $this->assertArrayHasKey('quiz', $gradeitems1); $this->assertArrayHasKey('manual', $gradeitems1); $this->assertArrayHasKey('assign', $gradeitems2); $this->assertArrayHasKey('manual', $gradeitems2); } /** * Test get_gradable_users() function. * * @covers ::get_gradable_users */ public function test_get_gradable_users(): void { global $DB; $this->setAdminUser(); $this->resetAfterTest(true); $roleteacher = $DB->get_record('role', ['shortname' => 'teacher'], '*', MUST_EXIST); // Create a course. $course = $this->getDataGenerator()->create_course(); $coursecontext = \context_course::instance($course->id); // Create groups. $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); // Create and enrol a teacher and some students into the course. $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); $student3 = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Add student1 and student2 to group1. $this->getDataGenerator()->create_group_member(['groupid' => $group1->id, 'userid' => $student1->id]); $this->getDataGenerator()->create_group_member(['groupid' => $group1->id, 'userid' => $student2->id]); // Add student3 to group2. $this->getDataGenerator()->create_group_member(['groupid' => $group2->id, 'userid' => $student3->id]); // Perform a regrade before creating the report. grade_regrade_final_grades($course->id); // Should return all gradable users (only students). $gradableusers = get_gradable_users($course->id); $this->assertEqualsCanonicalizing([$student1->id, $student2->id, $student3->id], array_keys($gradableusers)); // Now, let's suspend the enrolment of student2. $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student', 'manual', 0, 0, ENROL_USER_SUSPENDED); // Should return only the active gradable users (student1 and student3). $gradableusers = \grade_report::get_gradable_users($course->id); $this->assertEqualsCanonicalizing([$student1->id, $student3->id], array_keys($gradableusers)); // Give teacher 'viewsuspendedusers' capability and set a preference to display suspended users. assign_capability('moodle/course:viewsuspendedusers', CAP_ALLOW, $roleteacher->id, $coursecontext, true); set_user_preference('grade_report_showonlyactiveenrol', false, $teacher); accesslib_clear_all_caches_for_unit_testing(); $this->setUser($teacher); // Should return all gradable users (including suspended enrolments). $gradableusers = \grade_report::get_gradable_users($course->id); $this->assertEqualsCanonicalizing([$student1->id, $student2->id, $student3->id], array_keys($gradableusers)); // Reactivate the course enrolment of student2. $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student', 'manual', 0, 0, ENROL_USER_ACTIVE); $this->setAdminUser(); // Should return all gradable users from group1 (student1 and student2). $gradableusers = \grade_report::get_gradable_users($course->id, $group1->id); $this->assertEqualsCanonicalizing([$student1->id, $student2->id], array_keys($gradableusers)); // Should return all gradable users from group2 (student3). $gradableusers = \grade_report::get_gradable_users($course->id, $group2->id); $this->assertEqualsCanonicalizing([$student3->id], array_keys($gradableusers)); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/calendar/tests/lib_test.php000064400000145652152266601420024133 0ustar00. namespace core_calendar; /** * Class contaning unit tests for the calendar lib. * * @package core_calendar * @copyright 2017 Mark Nelson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { /** * Load required test libraries */ public static function setUpBeforeClass(): void { global $CFG; require_once("{$CFG->dirroot}/calendar/tests/helpers.php"); parent::setUpBeforeClass(); } /** * Tests set up */ protected function setUp(): void { parent::setUp(); $this->resetAfterTest(); } /** * Test that the get_events() function only returns activity events that are enabled. */ public function test_get_events_with_disabled_module(): void { global $DB; $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); $assigninstance = $assigngenerator->create_instance(['course' => $course->id]); $lessongenerator = $this->getDataGenerator()->get_plugin_generator('mod_lesson'); $lessoninstance = $lessongenerator->create_instance(['course' => $course->id]); $student = $generator->create_user(); $generator->enrol_user($student->id, $course->id, 'student'); $this->setUser($student); $events = [ [ 'name' => 'Start of assignment', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'assign', 'instance' => $assigninstance->id, 'eventtype' => 'due', 'timestart' => time(), 'timeduration' => 86400, 'visible' => 1 ], [ 'name' => 'Start of lesson', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'lesson', 'instance' => $lessoninstance->id, 'eventtype' => 'end', 'timestart' => time(), 'timeduration' => 86400, 'visible' => 1 ] ]; foreach ($events as $event) { \calendar_event::create($event, false); } $timestart = time() - 60; $timeend = time() + 60; // Get all events. $events = calendar_get_events($timestart, $timeend, true, 0, true); $this->assertCount(2, $events); // Disable the lesson module. $modulerecord = $DB->get_record('modules', ['name' => 'lesson']); $modulerecord->visible = 0; $DB->update_record('modules', $modulerecord); // Check that we only return the assign event. $events = calendar_get_events($timestart, $timeend, true, 0, true); $this->assertCount(1, $events); $event = reset($events); $this->assertEquals('assign', $event->modulename); } public function test_get_course_cached(): void { // Setup some test courses. $course1 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course3 = $this->getDataGenerator()->create_course(); // Load courses into cache. $coursecache = null; calendar_get_course_cached($coursecache, $course1->id); calendar_get_course_cached($coursecache, $course2->id); calendar_get_course_cached($coursecache, $course3->id); // Verify the cache. $this->assertArrayHasKey($course1->id, $coursecache); $cachedcourse1 = $coursecache[$course1->id]; $this->assertEquals($course1->id, $cachedcourse1->id); $this->assertEquals($course1->shortname, $cachedcourse1->shortname); $this->assertEquals($course1->fullname, $cachedcourse1->fullname); $this->assertArrayHasKey($course2->id, $coursecache); $cachedcourse2 = $coursecache[$course2->id]; $this->assertEquals($course2->id, $cachedcourse2->id); $this->assertEquals($course2->shortname, $cachedcourse2->shortname); $this->assertEquals($course2->fullname, $cachedcourse2->fullname); $this->assertArrayHasKey($course3->id, $coursecache); $cachedcourse3 = $coursecache[$course3->id]; $this->assertEquals($course3->id, $cachedcourse3->id); $this->assertEquals($course3->shortname, $cachedcourse3->shortname); $this->assertEquals($course3->fullname, $cachedcourse3->fullname); } /** * Test the update_subscription() function. */ public function test_update_subscription(): void { $this->resetAfterTest(true); $subscription = new \stdClass(); $subscription->eventtype = 'site'; $subscription->name = 'test'; $id = calendar_add_subscription($subscription); $subscription = calendar_get_subscription($id); $subscription->name = 'awesome'; calendar_update_subscription($subscription); $sub = calendar_get_subscription($id); $this->assertEquals($subscription->name, $sub->name); $subscription = calendar_get_subscription($id); $subscription->name = 'awesome2'; $subscription->pollinterval = 604800; calendar_update_subscription($subscription); $sub = calendar_get_subscription($id); $this->assertEquals($subscription->name, $sub->name); $this->assertEquals($subscription->pollinterval, $sub->pollinterval); $subscription = new \stdClass(); $subscription->name = 'awesome4'; $this->expectException('coding_exception'); calendar_update_subscription($subscription); } public function test_add_subscription(): void { global $DB, $CFG; require_once($CFG->dirroot . '/lib/bennu/bennu.inc.php'); $this->resetAfterTest(true); // Test for Microsoft Outlook 2010. $subscription = new \stdClass(); $subscription->name = 'Microsoft Outlook 2010'; $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; $subscription->eventtype = 'site'; $id = calendar_add_subscription($subscription); $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/ms_outlook_2010.ics'); $ical = new \iCalendar(); $ical->unserialize($calendar); $this->assertEquals($ical->parser_errors, array()); $sub = calendar_get_subscription($id); calendar_import_events_from_ical($ical, $sub->id); $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); $this->assertEquals($count, 1); // Test for OSX Yosemite. $subscription = new \stdClass(); $subscription->name = 'OSX Yosemite'; $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; $subscription->eventtype = 'site'; $id = calendar_add_subscription($subscription); $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/osx_yosemite.ics'); $ical = new \iCalendar(); $ical->unserialize($calendar); $this->assertEquals($ical->parser_errors, array()); $sub = calendar_get_subscription($id); calendar_import_events_from_ical($ical, $sub->id); $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); $this->assertEquals($count, 1); // Test for Google Gmail. $subscription = new \stdClass(); $subscription->name = 'Google Gmail'; $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; $subscription->eventtype = 'site'; $id = calendar_add_subscription($subscription); $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/google_gmail.ics'); $ical = new \iCalendar(); $ical->unserialize($calendar); $this->assertEquals($ical->parser_errors, array()); $sub = calendar_get_subscription($id); calendar_import_events_from_ical($ical, $sub->id); $count = $DB->count_records('event', array('subscriptionid' => $sub->id)); $this->assertEquals($count, 1); // Test for ICS file with repeated events. $subscription = new \stdClass(); $subscription->name = 'Repeated events'; $subscription->importfrom = CALENDAR_IMPORT_FROM_FILE; $subscription->eventtype = 'site'; $id = calendar_add_subscription($subscription); $calendar = file_get_contents($CFG->dirroot . '/lib/tests/fixtures/repeated_events.ics'); $ical = new \iCalendar(); $ical->unserialize($calendar); $this->assertEquals($ical->parser_errors, []); $sub = calendar_get_subscription($id); $output = calendar_import_events_from_ical($ical, $sub->id); $this->assertArrayHasKey('eventsimported', $output); $this->assertArrayHasKey('eventsskipped', $output); $this->assertArrayHasKey('eventsupdated', $output); $this->assertArrayHasKey('eventsdeleted', $output); $this->assertEquals(1, $output['eventsimported']); $this->assertEquals(0, $output['eventsskipped']); $this->assertEquals(0, $output['eventsupdated']); $this->assertEquals(0, $output['eventsdeleted']); } /** * Test for calendar_get_legacy_events() when there are user and group overrides. */ public function test_get_legacy_events_with_overrides(): void { $generator = $this->getDataGenerator(); $course = $generator->create_course(); $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); if (!isset($params['course'])) { $params['course'] = $course->id; } $instance = $plugingenerator->create_instance($params); // Create users. $useroverridestudent = $generator->create_user(); $group1student = $generator->create_user(); $group2student = $generator->create_user(); $group12student = $generator->create_user(); $nogroupstudent = $generator->create_user(); // Enrol users. $generator->enrol_user($useroverridestudent->id, $course->id, 'student'); $generator->enrol_user($group1student->id, $course->id, 'student'); $generator->enrol_user($group2student->id, $course->id, 'student'); $generator->enrol_user($group12student->id, $course->id, 'student'); $generator->enrol_user($nogroupstudent->id, $course->id, 'student'); // Create groups. $group1 = $generator->create_group(['courseid' => $course->id]); $group2 = $generator->create_group(['courseid' => $course->id]); // Add members to groups. $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group1student->id]); $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group2student->id]); $generator->create_group_member(['groupid' => $group1->id, 'userid' => $group12student->id]); $generator->create_group_member(['groupid' => $group2->id, 'userid' => $group12student->id]); $now = time(); // Events with the same module name, instance and event type. $events = [ [ 'name' => 'Assignment 1 due date', 'description' => '', 'location' => 'Test', 'format' => 0, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => 'due', 'timestart' => $now, 'timeduration' => 0, 'visible' => 1 ], [ 'name' => 'Assignment 1 due date - User override', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => 0, 'groupid' => 0, 'userid' => $useroverridestudent->id, 'modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => 'due', 'timestart' => $now + 86400, 'timeduration' => 0, 'visible' => 1, 'priority' => CALENDAR_EVENT_USER_OVERRIDE_PRIORITY ], [ 'name' => 'Assignment 1 due date - Group A override', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => $course->id, 'groupid' => $group1->id, 'userid' => 2, 'modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => 'due', 'timestart' => $now + (2 * 86400), 'timeduration' => 0, 'visible' => 1, 'priority' => 1, ], [ 'name' => 'Assignment 1 due date - Group B override', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => $course->id, 'groupid' => $group2->id, 'userid' => 2, 'modulename' => 'assign', 'instance' => $instance->id, 'eventtype' => 'due', 'timestart' => $now + (3 * 86400), 'timeduration' => 0, 'visible' => 1, 'priority' => 2, ], ]; foreach ($events as $event) { \calendar_event::create($event, false); } $timestart = $now - 100; $timeend = $now + (3 * 86400); $groups = [$group1->id, $group2->id]; // Get user override events. $this->setUser($useroverridestudent); $events = calendar_get_legacy_events($timestart, $timeend, $useroverridestudent->id, $groups, $course->id); $this->assertCount(1, $events); $event = reset($events); $this->assertEquals('Assignment 1 due date - User override', $event->name); // Get event for user with override but with the timestart and timeend parameters only covering the original event. $events = calendar_get_legacy_events($timestart, $now, $useroverridestudent->id, $groups, $course->id); $this->assertCount(0, $events); // Get events for user that does not belong to any group and has no user override events. $this->setUser($nogroupstudent); $events = calendar_get_legacy_events($timestart, $timeend, $nogroupstudent->id, $groups, $course->id); $this->assertCount(1, $events); $event = reset($events); $this->assertEquals('Assignment 1 due date', $event->name); // Get events for user that belongs to groups A and B and has no user override events. $this->setUser($group12student); $events = calendar_get_legacy_events($timestart, $timeend, $group12student->id, $groups, $course->id); $this->assertCount(1, $events); $event = reset($events); $this->assertEquals('Assignment 1 due date - Group A override', $event->name); // Get events for user that belongs to group A and has no user override events. $this->setUser($group1student); $events = calendar_get_legacy_events($timestart, $timeend, $group1student->id, $groups, $course->id); $this->assertCount(1, $events); $event = reset($events); $this->assertEquals('Assignment 1 due date - Group A override', $event->name); // Add repeating events. $repeatingevents = [ [ 'name' => 'Repeating site event', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => SITEID, 'groupid' => 0, 'userid' => 2, 'repeatid' => $event->id, 'modulename' => '0', 'instance' => 0, 'eventtype' => 'site', 'timestart' => $now + 86400, 'timeduration' => 0, 'visible' => 1, ], [ 'name' => 'Repeating site event', 'description' => '', 'location' => 'Test', 'format' => 1, 'courseid' => SITEID, 'groupid' => 0, 'userid' => 2, 'repeatid' => $event->id, 'modulename' => '0', 'instance' => 0, 'eventtype' => 'site', 'timestart' => $now + (2 * 86400), 'timeduration' => 0, 'visible' => 1, ], ]; foreach ($repeatingevents as $event) { \calendar_event::create($event, false); } // Make sure repeating events are not filtered out. $events = calendar_get_legacy_events($timestart, $timeend, true, true, true); $this->assertCount(3, $events); } public function test_calendar_get_default_courses(): void { global $USER, $CFG; $this->resetAfterTest(true); $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course1 = $generator->create_course(); $course2 = $generator->create_course(); $course3 = $generator->create_course(); $context = \context_course::instance($course1->id); $this->setAdminUser(); $admin = clone $USER; $teacher = $generator->create_user(); $generator->enrol_user($teacher->id, $course1->id, 'teacher'); $generator->enrol_user($admin->id, $course1->id, 'teacher'); $CFG->calendar_adminseesall = false; $courses = calendar_get_default_courses(); // Only enrolled in one course. $this->assertCount(1, $courses); $courses = calendar_get_default_courses($course2->id); // Enrolled course + current course. $this->assertCount(2, $courses); $CFG->calendar_adminseesall = true; $courses = calendar_get_default_courses(); // All courses + SITE. $this->assertCount(4, $courses); $courses = calendar_get_default_courses($course2->id); // All courses + SITE. $this->assertCount(4, $courses); $this->setUser($teacher); $CFG->calendar_adminseesall = false; $courses = calendar_get_default_courses(); // Only enrolled in one course. $this->assertCount(1, $courses); $courses = calendar_get_default_courses($course2->id); // Enrolled course only (ignore current). $this->assertCount(1, $courses); // This setting should not affect teachers. $CFG->calendar_adminseesall = true; $courses = calendar_get_default_courses(); // Only enrolled in one course. $this->assertCount(1, $courses); $courses = calendar_get_default_courses($course2->id); // Enrolled course only (ignore current). $this->assertCount(1, $courses); // Now, log out and test again. $this->setUser(); $CFG->calendar_adminseesall = false; $courses = calendar_get_default_courses(null, '*', false, $teacher->id); // Only enrolled in one course. $this->assertCount(1, $courses); $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id); // Enrolled course only (ignore current). $this->assertCount(1, $courses); // This setting should not affect teachers. $CFG->calendar_adminseesall = true; $courses = calendar_get_default_courses(null, '*', false, $teacher->id); // Only enrolled in one course. $this->assertCount(1, $courses); $courses = calendar_get_default_courses($course2->id, '*', false, $teacher->id); // Enrolled course only (ignore current). $this->assertCount(1, $courses); } /** * Confirm that the skip events flag causes the calendar_get_view function * to avoid querying for the calendar events. */ public function test_calendar_get_view_skip_events(): void { $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $user = $generator->create_user(); $skipnavigation = true; $skipevents = true; $event = create_event([ 'eventtype' => 'user', 'userid' => $user->id ]); $this->setUser($user); $calendar = \calendar_information::create(time() - 10, SITEID, null); list($data, $template) = calendar_get_view($calendar, 'day', $skipnavigation, $skipevents); $this->assertEmpty($data->events); $skipevents = false; list($data, $template) = calendar_get_view($calendar, 'day', $skipnavigation, $skipevents); $this->assertEquals($event->id, $data->events[0]->id); } public function test_calendar_get_allowed_event_types_course(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course1 = $generator->create_course(); // Has capability. $course2 = $generator->create_course(); // Doesn't have capability. $course3 = $generator->create_course(); // Not enrolled. $context1 = \context_course::instance($course1->id); $context2 = \context_course::instance($course2->id); $context3 = \context_course::instance($course3->id); $roleid = $generator->create_role(); $contexts = [$context1, $context2, $context3]; $enrolledcourses = [$course1, $course2]; foreach ($enrolledcourses as $course) { $generator->enrol_user($user->id, $course->id, 'student'); } foreach ($contexts as $context) { $generator->role_assign($roleid, $user->id, $context->id); } $this->setUser($user); // In general for all courses, they don't have the ability to add course events yet. $types = calendar_get_allowed_event_types(); $this->assertFalse($types['course']); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context1, true); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context2, true); // The user only has the correct capability in course 1 so that is the only // one that should be in the results. $types = calendar_get_allowed_event_types($course1->id); $this->assertTrue($types['course']); // If calling function without specified course, there is still a course where they have it. $types = calendar_get_allowed_event_types(); $this->assertTrue($types['course']); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context1, true); // The user only now has the correct capability in both course 1 and 2 so we // expect both to be in the results. $types = calendar_get_allowed_event_types($course3->id); $this->assertFalse($types['course']); // They now do not have permission in any course. $types = calendar_get_allowed_event_types(); $this->assertFalse($types['course']); } public function test_calendar_get_allowed_event_types_group_no_acces_to_diff_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); $this->setUser($user); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true); // The user has the correct capability in the course but they aren't a member // of any of the groups and don't have the accessallgroups capability. $types = calendar_get_allowed_event_types($course->id); $this->assertTrue($types['course']); $this->assertFalse($types['group']); // Same result applies when not providing a specific course as they are only on one course. $types = calendar_get_allowed_event_types(); $this->assertTrue($types['course']); $this->assertFalse($types['group']); } public function test_calendar_get_allowed_event_types_group_no_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); $this->setUser($user); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); // The user has the correct capability in the course but there are // no groups so we shouldn't see a group type. $types = calendar_get_allowed_event_types($course->id); $this->assertTrue($types['course']); $this->assertFalse($types['group']); // Same result applies when not providing a specific course as they are only on one course. $types = calendar_get_allowed_event_types(); $this->assertTrue($types['course']); $this->assertFalse($types['group']); } public function test_calendar_get_allowed_event_types_group_access_all_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course1 = $generator->create_course(); $course2 = $generator->create_course(); $generator->create_group(array('courseid' => $course1->id)); $generator->create_group(array('courseid' => $course2->id)); $context1 = \context_course::instance($course1->id); $context2 = \context_course::instance($course2->id); $roleid = $generator->create_role(); $generator->enrol_user($user->id, $course1->id, 'student'); $generator->enrol_user($user->id, $course2->id, 'student'); $generator->role_assign($roleid, $user->id, $context1->id); $generator->role_assign($roleid, $user->id, $context2->id); $this->setUser($user); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context1, true); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context2, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context1, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context2, true); // The user has the correct capability in the course and has // the accessallgroups capability. $types = calendar_get_allowed_event_types($course1->id); $this->assertTrue($types['group']); // Same result applies when not providing a specific course as they are only on one course. $types = calendar_get_allowed_event_types(); $this->assertTrue($types['group']); } public function test_calendar_get_allowed_event_types_group_no_access_all_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $group1 = $generator->create_group(array('courseid' => $course->id)); $group2 = $generator->create_group(array('courseid' => $course->id)); $roleid = $generator->create_role(); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); $generator->create_group_member(array('groupid' => $group1->id, 'userid' => $user->id)); $generator->create_group_member(array('groupid' => $group2->id, 'userid' => $user->id)); $this->setUser($user); assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $roleid, $context, true); // The user has the correct capability in the course but can't access // groups that they are not a member of. $types = calendar_get_allowed_event_types($course->id); $this->assertFalse($types['group']); // Same result applies when not providing a specific course as they are only on one course. $types = calendar_get_allowed_event_types(); $this->assertFalse($types['group']); assign_capability('moodle/calendar:manageentries', CAP_ALLOW, $roleid, $context, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true); $types = calendar_get_allowed_event_types($course->id); $this->assertTrue($types['group']); // Same result applies when not providing a specific course as they are only on one course. $types = calendar_get_allowed_event_types(); $this->assertTrue($types['group']); } public function test_calendar_get_allowed_event_types_group_cap_no_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $group = $generator->create_group(['courseid' => $course->id]); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true); $this->setUser($user); $types = calendar_get_allowed_event_types($course->id); $this->assertFalse($types['course']); $this->assertFalse($types['group']); // Check without specifying a course (same result as user only has one course). $types = calendar_get_allowed_event_types(); $this->assertFalse($types['course']); $this->assertFalse($types['group']); } public function test_calendar_get_allowed_event_types_group_cap_has_group(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $group = $generator->create_group(['courseid' => $course->id]); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); groups_add_member($group, $user); assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true); $this->setUser($user); $types = calendar_get_allowed_event_types($course->id); $this->assertFalse($types['course']); $this->assertTrue($types['group']); // Check without specifying a course (same result as user only has one course). $types = calendar_get_allowed_event_types(); $this->assertFalse($types['course']); $this->assertTrue($types['group']); } public function test_calendar_get_allowed_event_types_group_cap_access_all_groups(): void { $generator = $this->getDataGenerator(); $user = $generator->create_user(); $course = $generator->create_course(); $context = \context_course::instance($course->id); $roleid = $generator->create_role(); $group = $generator->create_group(['courseid' => $course->id]); $generator->enrol_user($user->id, $course->id, 'student'); $generator->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:managegroupentries', CAP_ALLOW, $roleid, $context, true); assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $context, true); $this->setUser($user); $types = calendar_get_allowed_event_types($course->id); $this->assertFalse($types['course']); $this->assertTrue($types['group']); // Check without specifying a course (same result as user only has one course). $types = calendar_get_allowed_event_types(); $this->assertFalse($types['course']); $this->assertTrue($types['group']); } /** * This is a setup helper function that create some users, courses, groups and group memberships. * This is useful to prepare the environment for testing the calendar_set_filters function. * * @return array An array of ($users, $courses, $coursegroups) */ protected function setup_test_calendar_set_filters() { $generator = $this->getDataGenerator(); // Create some users. $users = []; $users[] = $generator->create_user(); $users[] = $generator->create_user(); $users[] = $generator->create_user(); // Create some courses. $courses = []; $courses[] = $generator->create_course(); $courses[] = $generator->create_course(); $courses[] = $generator->create_course(); $courses[] = $generator->create_course(); // Create some groups. $coursegroups = []; $coursegroups[$courses[0]->id] = []; $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]); $coursegroups[$courses[0]->id][] = $generator->create_group(['courseid' => $courses[0]->id]); $coursegroups[$courses[2]->id] = []; $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]); $coursegroups[$courses[2]->id][] = $generator->create_group(['courseid' => $courses[2]->id]); $coursegroups[$courses[3]->id] = []; $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]); $coursegroups[$courses[3]->id][] = $generator->create_group(['courseid' => $courses[3]->id]); // Create some enrolments and group memberships. $generator->enrol_user($users[0]->id, $courses[0]->id, 'student'); $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][0]->id, 'userid' => $users[0]->id]); $generator->enrol_user($users[1]->id, $courses[0]->id, 'student'); $generator->create_group_member(['groupid' => $coursegroups[$courses[0]->id][1]->id, 'userid' => $users[1]->id]); $generator->enrol_user($users[0]->id, $courses[1]->id, 'student'); $generator->enrol_user($users[0]->id, $courses[2]->id, 'student'); return array($users, $courses, $coursegroups); } /** * This function tests calendar_set_filters for the case when user is not logged in. */ public function test_calendar_set_filters_not_logged_in(): void { $this->resetAfterTest(); list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters(); $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id); list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses); $this->assertEqualsCanonicalizing( [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID], array_values($courseids)); $this->assertFalse($groupids); $this->assertFalse($userid); } /** * This function tests calendar_set_filters for the case when no one is logged in, but a user id is provided. */ public function test_calendar_set_filters_not_logged_in_with_user(): void { $this->resetAfterTest(); list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters(); $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id); list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]); $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids)); $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids); $this->assertEquals($users[1]->id, $userid); $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id); list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[0]); $this->assertEqualsCanonicalizing( [$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID], array_values($courseids)); $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids); $this->assertEquals($users[0]->id, $userid); } /** * This function tests calendar_set_filters for the case when user is logged in, but no user id is provided. */ public function test_calendar_set_filters_logged_in_no_user(): void { $this->resetAfterTest(); list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters(); $this->setUser($users[0]); $defaultcourses = calendar_get_default_courses(null, '*', false, $users[0]->id); list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false); $this->assertEqualsCanonicalizing([$courses[0]->id, $courses[1]->id, $courses[2]->id, SITEID], array_values($courseids)); $this->assertEquals(array($coursegroups[$courses[0]->id][0]->id), $groupids); $this->assertEquals($users[0]->id, $userid); } /** * This function tests calendar_set_filters for the case when a user is logged in, but another user id is provided. */ public function test_calendar_set_filters_logged_in_another_user(): void { $this->resetAfterTest(); list($users, $courses, $coursegroups) = $this->setup_test_calendar_set_filters(); $this->setUser($users[0]); $defaultcourses = calendar_get_default_courses(null, '*', false, $users[1]->id); list($courseids, $groupids, $userid) = calendar_set_filters($defaultcourses, false, $users[1]); $this->assertEquals(array($courses[0]->id, SITEID), array_values($courseids)); $this->assertEquals(array($coursegroups[$courses[0]->id][1]->id), $groupids); $this->assertEquals($users[1]->id, $userid); } /** * This function tests calendar_set_filters for courses with separate group mode. */ public function test_calendar_set_filters_with_separate_group_mode(): void { global $DB; $this->resetAfterTest(); $generator = $this->getDataGenerator(); // Create users. $student1 = $generator->create_user(); $student2 = $generator->create_user(); $teacher1 = $generator->create_user(); $teacher2 = $generator->create_user(); // Create courses. $course1 = $generator->create_course([ 'shortname' => 'C1', 'groupmode' => 1, 'groupmodeforce' => 1, ]); $course2 = $generator->create_course([ 'shortname' => 'C2', 'groupmode' => 1, 'groupmodeforce' => 1, ]); $course1context = \context_course::instance($course1->id); $course2context = \context_course::instance($course2->id); // Create groups. $group1 = $generator->create_group([ 'name' => 'G1-C1', 'courseid' => $course1->id, ]); $group2 = $generator->create_group([ 'name' => 'G1-C2', 'courseid' => $course2->id, ]); $group3 = $generator->create_group([ 'name' => 'G2-C2', 'courseid' => $course2->id, ]); // Modify the capabilities. $editingteacherroleid = $DB->get_field('role', 'id', ['shortname' => 'editingteacher']); assign_capability( 'moodle/site:accessallgroups', CAP_PREVENT, $editingteacherroleid, $course1context->id, true ); assign_capability( 'moodle/site:accessallgroups', CAP_PREVENT, $editingteacherroleid, $course2context->id, true ); // Enrol users. $generator->enrol_user($student1->id, $course1->id, 'student'); $generator->enrol_user($teacher1->id, $course1->id, 'editingteacher'); $generator->enrol_user($student1->id, $course2->id, 'student'); $generator->enrol_user($student2->id, $course2->id, 'student'); $generator->enrol_user($teacher1->id, $course2->id, 'editingteacher'); $generator->enrol_user($teacher2->id, $course2->id, 'editingteacher'); // Group memberships. $generator->create_group_member([ 'groupid' => $group1->id, 'userid' => $student1->id, ]); $generator->create_group_member([ 'groupid' => $group1->id, 'userid' => $teacher1->id, ]); $generator->create_group_member([ 'groupid' => $group2->id, 'userid' => $student1->id, ]); $generator->create_group_member([ 'groupid' => $group2->id, 'userid' => $teacher1->id, ]); $generator->create_group_member([ 'groupid' => $group3->id, 'userid' => $student2->id, ]); $generator->create_group_member([ 'groupid' => $group3->id, 'userid' => $teacher2->id, ]); // Test teacher1. $this->setUser($teacher1); $defaultcourses = calendar_get_default_courses( null, '*', false, $teacher1->id ); [$courseids, $groupids] = calendar_set_filters( $defaultcourses, false, $teacher1 ); // Teacher1 can see SITE, C1, G1-C1, C2, G1-C2. $this->assertCount(3, $courseids); // SITE, C1, C2. $this->assertCount(2, $groupids); // G1-C1, G1-C2. $courseidskey = array_fill_keys($courseids, null); $this->assertArrayHasKey(SITEID, $courseidskey); $this->assertArrayHasKey($course1->id, $courseidskey); $this->assertArrayHasKey($course2->id, $courseidskey); $groupidskey = array_fill_keys($groupids, null); $this->assertArrayHasKey($group1->id, $groupidskey); $this->assertArrayHasKey($group2->id, $groupidskey); $this->assertArrayNotHasKey($group3->id, $groupidskey); // Test teacher2. $this->setUser($teacher2); $defaultcourses = calendar_get_default_courses( null, '*', false, $teacher2->id ); [$courseids, $groupids] = calendar_set_filters( $defaultcourses, false, $teacher2 ); // Teacher2 can see SITE, C2, G2-C2. $this->assertCount(2, $courseids); // SITE, C2. $this->assertCount(1, $groupids); // G2-C2. $courseidskey = array_fill_keys($courseids, null); $this->assertArrayHasKey(SITEID, $courseidskey); $this->assertArrayHasKey($course2->id, $courseidskey); $groupidskey = array_fill_keys($groupids, null); $this->assertArrayHasKey($group3->id, $groupidskey); $this->assertArrayNotHasKey($group1->id, $groupidskey); $this->assertArrayNotHasKey($group2->id, $groupidskey); // Modify the capabilities. assign_capability( 'moodle/site:accessallgroups', CAP_ALLOW, $editingteacherroleid, $course2context->id, true ); $defaultcourses = calendar_get_default_courses( null, '*', false, $teacher2->id ); [$courseids, $groupids] = calendar_set_filters( $defaultcourses, false, $teacher2 ); // Teacher2 can see SITE, C2, G1-C2, G2-C2. $this->assertCount(2, $courseids); // SITE, C2. $this->assertCount(2, $groupids); // G1-C2, G2-C2. $groupidskey = array_fill_keys($groupids, null); $this->assertArrayHasKey($group2->id, $groupidskey); $this->assertArrayHasKey($group3->id, $groupidskey); $this->assertArrayNotHasKey($group1->id, $groupidskey); } /** * Test for calendar_view_event_allowed for course event types. */ public function test_calendar_view_event_allowed_course_event(): void { global $USER; $this->setAdminUser(); $generator = $this->getDataGenerator(); // A student in a course. $student = $generator->create_user(); // Some user not enrolled in any course. $someuser = $generator->create_user(); // A course with manual enrolments. $manualcourse = $generator->create_course(); // Enrol the student to the manual enrolment course. $generator->enrol_user($student->id, $manualcourse->id); // A course that allows guest access. $guestcourse = $generator->create_course( (object)[ 'shortname' => 'guestcourse', 'enrol_guest_status_0' => ENROL_INSTANCE_ENABLED, 'enrol_guest_password_0' => '' ]); $manualevent = (object)[ 'name' => 'Manual course event', 'description' => '', 'format' => 1, 'categoryid' => 0, 'courseid' => $manualcourse->id, 'groupid' => 0, 'userid' => $USER->id, 'modulename' => 0, 'instance' => 0, 'eventtype' => 'course', 'timestart' => time(), 'timeduration' => 86400, 'visible' => 1 ]; $caleventmanual = \calendar_event::create($manualevent, false); // Create a course event for the course with guest access. $guestevent = clone $manualevent; $guestevent->name = 'Guest course event'; $guestevent->courseid = $guestcourse->id; $caleventguest = \calendar_event::create($guestevent, false); // Viewing as admin. $this->assertTrue(calendar_view_event_allowed($caleventmanual)); $this->assertTrue(calendar_view_event_allowed($caleventguest)); // Viewing as someone enrolled in a course. $this->setUser($student); $this->assertTrue(calendar_view_event_allowed($caleventmanual)); // Viewing as someone not enrolled in any course. $this->setUser($someuser); // Viewing as someone not enrolled in a course without guest access on. $this->assertFalse(calendar_view_event_allowed($caleventmanual)); // Viewing as someone not enrolled in a course with guest access on. $this->assertTrue(calendar_view_event_allowed($caleventguest)); } /** * Test for calendar_get_export_token for current user. */ public function test_calendar_get_export_token_for_current_user(): void { global $USER, $DB, $CFG; $this->setAdminUser(); // Get my token. $authtoken = calendar_get_export_token($USER); $expected = sha1($USER->id . $DB->get_field('user', 'password', ['id' => $USER->id]) . $CFG->calendar_exportsalt); $this->assertEquals($expected, $authtoken); } /** * Test for calendar_get_export_token for another user. */ public function test_calendar_get_export_token_for_another_user(): void { global $CFG; // Get any user token. $generator = $this->getDataGenerator(); $user = $generator->create_user(); // Get other user token. $authtoken = calendar_get_export_token($user); $expected = sha1($user->id . $user->password . $CFG->calendar_exportsalt); $this->assertEquals($expected, $authtoken); } /** * Test calendar_can_manage_user_event for different users. * * @covers ::calendar_can_manage_user_event */ public function test_calendar_can_manage_user_event(): void { global $DB, $USER; $generator = $this->getDataGenerator(); $sitecontext = \context_system::instance(); $this->resetAfterTest(); $this->setAdminUser(); $user1 = $generator->create_user(); $user2 = $generator->create_user(); $adminevent = create_event([ 'eventtype' => 'user', 'userid' => $USER->id, ]); $this->setUser($user1); $user1event = create_event([ 'name' => 'user1 event', 'eventtype' => 'user', 'userid' => $user1->id, ]); $this->setUser($user2); $user2event = create_event([ 'name' => 'user2 event', 'eventtype' => 'user', 'userid' => $user2->id, ]); $this->setUser($user1); $result = calendar_can_manage_user_event($user1event); $this->assertEquals(true, $result); $result = calendar_can_manage_user_event($user2event); $this->assertEquals(false, $result); $sitemanager = $generator->create_user(); $managerroleid = $DB->get_field('role', 'id', ['shortname' => 'manager']); role_assign($managerroleid, $sitemanager->id, $sitecontext->id); $this->setUser($sitemanager); $result = calendar_can_manage_user_event($user1event); $this->assertEquals(true, $result); $result = calendar_can_manage_user_event($adminevent); $this->assertEquals(false, $result); } /** * Data provider for {@see test_calendar_format_event_location} * * @return array[] */ public static function calendar_format_event_location_provider(): array { return [ 'Empty' => ['', ''], 'Text' => ['Barcelona', 'Barcelona'], 'Link (http)' => ['http://example.com', 'http://example.com'], 'Link (https)' => ['https://example.com', 'https://example.com'], ]; } /** * Test formatting event location * * @param string $location * @param string $expectedpattern * * @covers ::calendar_format_event_location * @dataProvider calendar_format_event_location_provider */ public function test_calendar_format_event_location(string $location, string $expectedpattern): void { $this->resetAfterTest(); $this->setAdminUser(); $event = create_event(['location' => $location]); $this->assertMatchesRegularExpression("|^({$expectedpattern})$|", calendar_format_event_location($event)); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/enrol/guest/tests/lib_test.php000064400000012167152266665370024640 0ustar00. /** * Guest enrolment tests. * * @package enrol_guest * @category phpunit * @copyright 2023 Ilya Tregubov * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace enrol_guest; final class lib_test extends \advanced_testcase { /** * Test the behaviour of validate_enrol_plugin_data(). * * @covers ::validate_enrol_plugin_data */ public function test_validate_enrol_plugin_data(): void { global $CFG; $this->resetAfterTest(); $guestplugin = enrol_get_plugin('guest'); $guestplugin->set_config('usepasswordpolicy', false); $enrolmentdata = []; $errors = $guestplugin->validate_enrol_plugin_data($enrolmentdata); $this->assertEmpty($errors); // Now enable some controls, and check that the policy responds with policy text. $guestplugin->set_config('usepasswordpolicy', true); $CFG->minpasswordlength = 8; $CFG->minpassworddigits = 1; $CFG->minpasswordlower = 1; $CFG->minpasswordupper = 1; $CFG->minpasswordnonalphanum = 1; $CFG->maxconsecutiveidentchars = 1; $errors = $guestplugin->validate_enrol_plugin_data($enrolmentdata); // If password is omitted it will be autocreated so nothing to validate. $this->assertEmpty($errors); $enrolmentdata = ['password' => 'test']; $errors = $guestplugin->validate_enrol_plugin_data($enrolmentdata); $this->assertCount(4, $errors); $this->assertEquals(get_string('errorminpasswordlength', 'auth', $CFG->minpasswordlength), $errors['enrol_guest0']); $this->assertEquals(get_string('errorminpassworddigits', 'auth', $CFG->minpassworddigits), $errors['enrol_guest1']); $this->assertEquals(get_string('errorminpasswordupper', 'auth', $CFG->minpasswordupper), $errors['enrol_guest2']); $this->assertEquals(get_string('errorminpasswordnonalphanum', 'auth', $CFG->minpasswordnonalphanum), $errors['enrol_guest3']); $enrolmentdata = ['password' => 'Testingtest123@']; $errors = $guestplugin->validate_enrol_plugin_data($enrolmentdata); $this->assertEmpty($errors); } /** * Test the behaviour of update_enrol_plugin_data(). * * @covers ::update_enrol_plugin_data */ public function test_update_enrol_plugin_data(): void { global $DB; $this->resetAfterTest(); $manualplugin = enrol_get_plugin('guest'); $admin = get_admin(); $this->setUser($admin); $enrolmentdata = []; $cat = $this->getDataGenerator()->create_category(); $course = $this->getDataGenerator()->create_course(['category' => $cat->id, 'shortname' => 'ANON']); $instance = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'guest'], '*', MUST_EXIST); $expectedinstance = $instance; $modifiedinstance = $manualplugin->update_enrol_plugin_data($course->id, $enrolmentdata, $instance); $this->assertEquals($expectedinstance, $modifiedinstance); $enrolmentdata['password'] = 'test'; $expectedinstance->password = 'test'; $modifiedinstance = $manualplugin->update_enrol_plugin_data($course->id, $enrolmentdata, $instance); $this->assertEquals($expectedinstance, $modifiedinstance); } /** * Test the behaviour of find_instance(). * * @covers ::find_instance */ public function test_find_instance(): void { global $DB; $this->resetAfterTest(); $cat = $this->getDataGenerator()->create_category(); // When we create a course, a guest enrolment instance is also created. $course = $this->getDataGenerator()->create_course(['category' => $cat->id, 'shortname' => 'ANON']); $guestplugin = enrol_get_plugin('guest'); $expected = $DB->get_record('enrol', ['courseid' => $course->id, 'enrol' => 'guest']); // Let's try to add second instance - only 1 guest instance is possible. $instanceid2 = null; // Have to do this check since add_instance doesn't block adding second instance for guest plugin. if ($guestplugin->can_add_instance($course->id)) { $instanceid2 = $guestplugin->add_instance($course, []); } $this->assertNull($instanceid2); $enrolmentdata = []; $actual = $guestplugin->find_instance($enrolmentdata, $course->id); $this->assertEquals($expected->id, $actual->id); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/url/tests/lib_test.php000064400000027006152267022700023732 0ustar00. /** * Unit tests for some mod URL lib stuff. * * @package mod_url * @category phpunit * @copyright 2012 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace mod_url; defined('MOODLE_INTERNAL') || die(); /** * mod_url tests * * @package mod_url * @category phpunit * @copyright 2011 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { /** * Prepares things before this test case is initialised * @return void */ public static function setUpBeforeClass(): void { global $CFG; require_once($CFG->dirroot . '/mod/url/lib.php'); require_once($CFG->dirroot . '/mod/url/locallib.php'); parent::setUpBeforeClass(); } /** * Tests the url_appears_valid_url function * @return void */ public function test_url_appears_valid_url(): void { $this->assertTrue(url_appears_valid_url('http://example')); $this->assertTrue(url_appears_valid_url('http://www.example.com')); $this->assertTrue(url_appears_valid_url('http://www.examplé.com')); $this->assertTrue(url_appears_valid_url('http://💩.la')); $this->assertTrue(url_appears_valid_url('http://香港大學.香港')); $this->assertTrue(url_appears_valid_url('http://وزارة-الأتصالات.مصر')); $this->assertTrue(url_appears_valid_url('http://www.теннис-алт.рф')); $this->assertTrue(url_appears_valid_url('http://имена.бг')); $this->assertTrue(url_appears_valid_url('http://straße.de')); $this->assertTrue(url_appears_valid_url('http://キース.コム')); $this->assertTrue(url_appears_valid_url('http://太亞.中国')); $this->assertTrue(url_appears_valid_url('http://www.რეგისტრაცია.გე')); $this->assertTrue(url_appears_valid_url('http://уміц.укр')); $this->assertTrue(url_appears_valid_url('http://현대.한국')); $this->assertTrue(url_appears_valid_url('http://мон.мон')); $this->assertTrue(url_appears_valid_url('http://тест.қаз')); $this->assertTrue(url_appears_valid_url('http://рнидс.срб')); $this->assertTrue(url_appears_valid_url('http://اسماء.شبكة')); $this->assertTrue(url_appears_valid_url('http://www.informationssäkerhet.se')); $this->assertTrue(url_appears_valid_url('http://москва.рф/services')); $this->assertTrue(url_appears_valid_url('http://detdumærker.dk')); $this->assertTrue(url_appears_valid_url('http://www.exa-mple2.com')); $this->assertTrue(url_appears_valid_url('http://www.example.com/~nobody/index.html')); $this->assertTrue(url_appears_valid_url('http://www.example.com#hmm')); $this->assertTrue(url_appears_valid_url('http://www.example.com/#hmm')); $this->assertTrue(url_appears_valid_url('http://www.example.com/žlutý koníček/lala.txt')); $this->assertTrue(url_appears_valid_url('http://www.example.com/žlutý koníček/lala.txt#hmmmm')); $this->assertTrue(url_appears_valid_url('http://www.example.com/index.php?xx=yy&zz=aa')); $this->assertTrue(url_appears_valid_url('http://www.example.com:80/index.php?xx=yy&zz=aa')); $this->assertTrue(url_appears_valid_url('https://user:password@www.example.com/žlutý koníček/lala.txt')); $this->assertTrue(url_appears_valid_url('ftp://user:password@www.example.com/žlutý koníček/lala.txt')); $this->assertFalse(url_appears_valid_url('http:example.com')); $this->assertFalse(url_appears_valid_url('http:/example.com')); $this->assertFalse(url_appears_valid_url('http://')); $this->assertFalse(url_appears_valid_url('http://www.exa mple.com')); $this->assertFalse(url_appears_valid_url('http://@www.example.com')); $this->assertFalse(url_appears_valid_url('http://user:@www.example.com')); $this->assertTrue(url_appears_valid_url('lalala://@:@/')); } /** * Test url_view * @return void */ public function test_url_view(): void { global $CFG; $CFG->enablecompletion = 1; $this->resetAfterTest(); // Setup test data. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $url = $this->getDataGenerator()->create_module('url', array('course' => $course->id), array('completion' => 2, 'completionview' => 1)); $context = \context_module::instance($url->cmid); $cm = get_coursemodule_from_instance('url', $url->id); // Trigger and capture the event. $sink = $this->redirectEvents(); $this->setAdminUser(); url_view($url, $course, $cm, $context); $events = $sink->get_events(); // 2 additional events thanks to completion. $this->assertCount(3, $events); $event = array_shift($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_url\event\course_module_viewed', $event); $this->assertEquals($context, $event->get_context()); $url = new \moodle_url('/mod/url/view.php', array('id' => $cm->id)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); $this->assertNotEmpty($event->get_name()); // Check completion status. $completion = new \completion_info($course); $completiondata = $completion->get_data($cm); $this->assertEquals(1, $completiondata->completionstate); } /** * Test mod_url_core_calendar_provide_event_action with user override */ public function test_url_core_calendar_provide_event_action_user_override(): void { global $CFG, $USER; $this->resetAfterTest(); $this->setAdminUser(); $user = $this->getDataGenerator()->create_user(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $url = $this->getDataGenerator()->create_module('url', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Get some additional data. $cm = get_coursemodule_from_instance('url', $url->id); // Create a calendar event. $event = $this->create_action_event($course->id, $url->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_url_core_calendar_provide_event_action($event, $factory, $USER->id); // Decorate action with a userid override. $actionevent2 = mod_url_core_calendar_provide_event_action($event, $factory, $user->id); // Ensure result was null because it has been marked as completed for the associated user. // Logic was brought across from the "_already_completed" function. $this->assertNull($actionevent); // Confirm the event was decorated. $this->assertNotNull($actionevent2); $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent2); $this->assertEquals(get_string('view'), $actionevent2->get_name()); $this->assertInstanceOf('moodle_url', $actionevent2->get_url()); $this->assertEquals(1, $actionevent2->get_item_count()); $this->assertTrue($actionevent2->is_actionable()); } public function test_url_core_calendar_provide_event_action(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $url = $this->getDataGenerator()->create_module('url', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $url->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_url_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('view'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_url_core_calendar_provide_event_action_already_completed(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $url = $this->getDataGenerator()->create_module('url', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Get some additional data. $cm = get_coursemodule_from_instance('url', $url->id); // Create a calendar event. $event = $this->create_action_event($course->id, $url->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_url_core_calendar_provide_event_action($event, $factory); // Ensure result was null. $this->assertNull($actionevent); } /** * Creates an action event. * * @param int $courseid The course id. * @param int $instanceid The instance id. * @param string $eventtype The event type. * @return bool|calendar_event */ private function create_action_event($courseid, $instanceid, $eventtype) { $event = new \stdClass(); $event->name = 'Calendar event'; $event->modulename = 'url'; $event->courseid = $courseid; $event->instance = $instanceid; $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->eventtype = $eventtype; $event->timestart = time(); return \calendar_event::create($event); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/quiz/tests/lib_test.php000064400000132611152267023630024122 0ustar00. /** * Unit tests for (some of) mod/quiz/locallib.php. * * @package mod_quiz * @category test * @copyright 2008 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU Public License */ namespace mod_quiz; use context_module; use core_external\external_api; use mod_quiz\quiz_settings; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/quiz/lib.php'); require_once($CFG->dirroot . '/mod/quiz/tests/quiz_question_helper_test_trait.php'); /** * @copyright 2008 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU Public License */ final class lib_test extends \advanced_testcase { use \quiz_question_helper_test_trait; public function test_quiz_has_grades(): void { $quiz = new \stdClass(); $quiz->grade = '100.0000'; $quiz->sumgrades = '100.0000'; $this->assertTrue(quiz_has_grades($quiz)); $quiz->sumgrades = '0.0000'; $this->assertFalse(quiz_has_grades($quiz)); $quiz->grade = '0.0000'; $this->assertFalse(quiz_has_grades($quiz)); $quiz->sumgrades = '100.0000'; $this->assertFalse(quiz_has_grades($quiz)); } public function test_quiz_format_grade(): void { $quiz = new \stdClass(); $quiz->decimalpoints = 2; $this->assertEquals(quiz_format_grade($quiz, 0.12345678), format_float(0.12, 2)); $this->assertEquals(quiz_format_grade($quiz, 0), format_float(0, 2)); $this->assertEquals(quiz_format_grade($quiz, 1.000000000000), format_float(1, 2)); $quiz->decimalpoints = 0; $this->assertEquals(quiz_format_grade($quiz, 0.12345678), '0'); } public function test_quiz_get_grade_format(): void { $quiz = new \stdClass(); $quiz->decimalpoints = 2; $this->assertEquals(quiz_get_grade_format($quiz), 2); $this->assertEquals($quiz->questiondecimalpoints, -1); $quiz->questiondecimalpoints = 2; $this->assertEquals(quiz_get_grade_format($quiz), 2); $quiz->decimalpoints = 3; $quiz->questiondecimalpoints = -1; $this->assertEquals(quiz_get_grade_format($quiz), 3); $quiz->questiondecimalpoints = 4; $this->assertEquals(quiz_get_grade_format($quiz), 4); } public function test_quiz_format_question_grade(): void { $quiz = new \stdClass(); $quiz->decimalpoints = 2; $quiz->questiondecimalpoints = 2; $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.12, 2)); $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 2)); $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 2)); $quiz->decimalpoints = 3; $quiz->questiondecimalpoints = -1; $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.123, 3)); $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 3)); $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 3)); $quiz->questiondecimalpoints = 4; $this->assertEquals(quiz_format_question_grade($quiz, 0.12345678), format_float(0.1235, 4)); $this->assertEquals(quiz_format_question_grade($quiz, 0), format_float(0, 4)); $this->assertEquals(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 4)); } /** * Test deleting a quiz instance. */ public function test_quiz_delete_instance(): void { global $SITE, $DB; $this->resetAfterTest(true); $this->setAdminUser(); // Setup a quiz with 1 standard and 1 random question. $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); $quiz = $quizgenerator->create_instance(['course' => $SITE->id, 'questionsperpage' => 3, 'grade' => 100.0]); $context = context_module::instance($quiz->cmid); $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $standardq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); quiz_add_quiz_question($standardq->id, $quiz); $this->add_random_questions($quiz->id, 0, $cat->id, 1); // Get the random question. $randomq = $DB->get_record('question', ['qtype' => 'random']); quiz_delete_instance($quiz->id); // Check that the random question was deleted. if ($randomq) { $this->assertEquals(0, $DB->count_records('question', ['id' => $randomq->id])); } // Check that the standard question was not deleted. $this->assertEquals(1, $DB->count_records('question', ['id' => $standardq->id])); // Check that all the slots were removed. $this->assertEquals(0, $DB->count_records('quiz_slots', ['quizid' => $quiz->id])); // Check that the quiz was removed. $this->assertEquals(0, $DB->count_records('quiz', ['id' => $quiz->id])); // Check that any question references linked to this quiz are gone. $this->assertEquals(0, $DB->count_records('question_references', ['usingcontextid' => $context->id])); $this->assertEquals(0, $DB->count_records('question_set_references', ['usingcontextid' => $context->id])); } /** * Test deleting a quiz when the course is deleted. * * @covers ::quiz_delete_instance */ public function test_quiz_when_delete_course(): void { global $DB, $USER; $this->resetAfterTest(); $this->setAdminUser(); // Step 1: Create one course and a user with editing teacher capabilities. $generator = $this->getDataGenerator(); $course = $generator->create_course(); $teacher = $USER; $generator->enrol_user($teacher->id, $course->id, 'editingteacher'); // Create a quiz with questions in the first course. $quiz = $this->create_test_quiz($course); $context = \context_module::instance($quiz->cmid); // Create questions. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(['contextid' => $context->id]); $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); // Add to the quiz. quiz_add_quiz_question($saq->id, $quiz); // Delete the course. delete_course($course, false); // Check that the question was deleted. $this->assertFalse($DB->record_exists('question', ['id' => $saq->id])); // Check that all the slots were removed. $this->assertFalse($DB->record_exists('quiz_slots', ['quizid' => $quiz->id])); // Check that the quiz was removed. $this->assertFalse($DB->record_exists('quiz', ['id' => $quiz->id])); // Check that any question references linked to this quiz are gone. $this->assertFalse($DB->record_exists('question_references', ['usingcontextid' => $context->id])); $this->assertFalse($DB->record_exists('question_set_references', ['usingcontextid' => $context->id])); } public function test_quiz_get_user_attempts(): void { global $DB; $this->resetAfterTest(); $dg = $this->getDataGenerator(); $quizgen = $dg->get_plugin_generator('mod_quiz'); $course = $dg->create_course(); $u1 = $dg->create_user(); $u2 = $dg->create_user(); $u3 = $dg->create_user(); $u4 = $dg->create_user(); $role = $DB->get_record('role', ['shortname' => 'student']); $dg->enrol_user($u1->id, $course->id, $role->id); $dg->enrol_user($u2->id, $course->id, $role->id); $dg->enrol_user($u3->id, $course->id, $role->id); $dg->enrol_user($u4->id, $course->id, $role->id); $quiz1 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]); $quiz2 = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]); // Questions. $questgen = $dg->get_plugin_generator('core_question'); $quizcat = $questgen->create_question_category(); $question = $questgen->create_question('numerical', null, ['category' => $quizcat->id]); quiz_add_quiz_question($question->id, $quiz1); quiz_add_quiz_question($question->id, $quiz2); $quizobj1a = quiz_settings::create($quiz1->id, $u1->id); $quizobj1b = quiz_settings::create($quiz1->id, $u2->id); $quizobj1c = quiz_settings::create($quiz1->id, $u3->id); $quizobj1d = quiz_settings::create($quiz1->id, $u4->id); $quizobj2a = quiz_settings::create($quiz2->id, $u1->id); // Set attempts. $quba1a = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1a->get_context()); $quba1a->set_preferred_behaviour($quizobj1a->get_quiz()->preferredbehaviour); $quba1b = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1b->get_context()); $quba1b->set_preferred_behaviour($quizobj1b->get_quiz()->preferredbehaviour); $quba1c = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1c->get_context()); $quba1c->set_preferred_behaviour($quizobj1c->get_quiz()->preferredbehaviour); $quba1d = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj1d->get_context()); $quba1d->set_preferred_behaviour($quizobj1d->get_quiz()->preferredbehaviour); $quba2a = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context()); $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour); $timenow = time(); // User 1 passes quiz 1. $attempt = quiz_create_attempt($quizobj1a, 1, false, $timenow, false, $u1->id); quiz_start_new_attempt($quizobj1a, $quba1a, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj1a, $quba1a, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submitted_actions($timenow, false, [1 => ['answer' => '3.14']]); $attemptobj->process_submit($timenow, false); $attemptobj->process_grade_submission($timenow); // User 2 goes overdue in quiz 1. $attempt = quiz_create_attempt($quizobj1b, 1, false, $timenow, false, $u2->id); quiz_start_new_attempt($quizobj1b, $quba1b, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj1b, $quba1b, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_going_overdue($timenow, true); // User 3 does not finish quiz 1. $attempt = quiz_create_attempt($quizobj1c, 1, false, $timenow, false, $u3->id); quiz_start_new_attempt($quizobj1c, $quba1c, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj1c, $quba1c, $attempt); // User 4 abandons the quiz 1. $attempt = quiz_create_attempt($quizobj1d, 1, false, $timenow, false, $u4->id); quiz_start_new_attempt($quizobj1d, $quba1d, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj1d, $quba1d, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_abandon($timenow, true); // User 1 attempts the quiz three times (abandon, finish, in progress). $quba2a = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context()); $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour); $attempt = quiz_create_attempt($quizobj2a, 1, false, $timenow, false, $u1->id); quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj2a, $quba2a, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_abandon($timenow, true); $quba2a = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context()); $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour); $attempt = quiz_create_attempt($quizobj2a, 2, false, $timenow, false, $u1->id); quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 2, $timenow); quiz_attempt_save_started($quizobj2a, $quba2a, $attempt); $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submit($timenow, false); $attemptobj->process_grade_submission($timenow); $quba2a = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj2a->get_context()); $quba2a->set_preferred_behaviour($quizobj2a->get_quiz()->preferredbehaviour); $attempt = quiz_create_attempt($quizobj2a, 3, false, $timenow, false, $u1->id); quiz_start_new_attempt($quizobj2a, $quba2a, $attempt, 3, $timenow); quiz_attempt_save_started($quizobj2a, $quba2a, $attempt); // Check for user 1. $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'all'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'finished'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u1->id, 'unfinished'); $this->assertCount(0, $attempts); // Check for user 2. $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'all'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state); $this->assertEquals($u2->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'finished'); $this->assertCount(0, $attempts); $attempts = quiz_get_user_attempts($quiz1->id, $u2->id, 'unfinished'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::OVERDUE, $attempt->state); $this->assertEquals($u2->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); // Check for user 3. $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'all'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state); $this->assertEquals($u3->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'finished'); $this->assertCount(0, $attempts); $attempts = quiz_get_user_attempts($quiz1->id, $u3->id, 'unfinished'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state); $this->assertEquals($u3->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); // Check for user 4. $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'all'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state); $this->assertEquals($u4->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'finished'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state); $this->assertEquals($u4->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz1->id, $u4->id, 'unfinished'); $this->assertCount(0, $attempts); // Multiple attempts for user 1 in quiz 2. $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'all'); $this->assertCount(3, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'finished'); $this->assertCount(2, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $attempts = quiz_get_user_attempts($quiz2->id, $u1->id, 'unfinished'); $this->assertCount(1, $attempts); $attempt = array_shift($attempts); // Multiple quiz attempts fetched at once. $attempts = quiz_get_user_attempts([$quiz1->id, $quiz2->id], $u1->id, 'all'); $this->assertCount(4, $attempts); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz1->id, $attempt->quiz); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::ABANDONED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::FINISHED, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); $attempt = array_shift($attempts); $this->assertEquals(quiz_attempt::IN_PROGRESS, $attempt->state); $this->assertEquals($u1->id, $attempt->userid); $this->assertEquals($quiz2->id, $attempt->quiz); } /** * Test for quiz_get_group_override_priorities(). */ public function test_quiz_get_group_override_priorities(): void { global $DB; $this->resetAfterTest(); $dg = $this->getDataGenerator(); $quizgen = $dg->get_plugin_generator('mod_quiz'); $course = $dg->create_course(); $quiz = $quizgen->create_instance(['course' => $course->id, 'sumgrades' => 2]); $this->assertNull(quiz_get_group_override_priorities($quiz->id)); $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); $now = 100; $override1 = (object)[ 'quiz' => $quiz->id, 'groupid' => $group1->id, 'timeopen' => $now, 'timeclose' => $now + 20 ]; $DB->insert_record('quiz_overrides', $override1); $override2 = (object)[ 'quiz' => $quiz->id, 'groupid' => $group2->id, 'timeopen' => $now - 10, 'timeclose' => $now + 10 ]; $DB->insert_record('quiz_overrides', $override2); $priorities = quiz_get_group_override_priorities($quiz->id); $this->assertNotEmpty($priorities); $openpriorities = $priorities['open']; // Override 2's time open has higher priority since it is sooner than override 1's. $this->assertEquals(2, $openpriorities[$override1->timeopen]); $this->assertEquals(1, $openpriorities[$override2->timeopen]); $closepriorities = $priorities['close']; // Override 1's time close has higher priority since it is later than override 2's. $this->assertEquals(1, $closepriorities[$override1->timeclose]); $this->assertEquals(2, $closepriorities[$override2->timeclose]); } public function test_quiz_core_calendar_provide_event_action_open(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student and enrol into the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeopen' => time() - DAYSECS, 'timeclose' => time() + DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Now, log in as student. $this->setUser($student); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_quiz_core_calendar_provide_event_action_open_for_user(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student and enrol into the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeopen' => time() - DAYSECS, 'timeclose' => time() + DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_quiz_core_calendar_provide_event_action_closed(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeclose' => time() - DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE); // Create an action factory. $factory = new \core_calendar\action_factory(); // Confirm the result was null. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory)); } public function test_quiz_core_calendar_provide_event_action_closed_for_user(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeclose' => time() - DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE); // Create an action factory. $factory = new \core_calendar\action_factory(); // Confirm the result was null. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id)); } public function test_quiz_core_calendar_provide_event_action_open_in_future(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student and enrol into the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeopen' => time() + DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE); // Now, log in as student. $this->setUser($student); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertFalse($actionevent->is_actionable()); } public function test_quiz_core_calendar_provide_event_action_open_in_future_for_user(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student and enrol into the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'timeopen' => time() + DAYSECS]); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_CLOSE); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('attemptquiznow', 'quiz'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertFalse($actionevent->is_actionable()); } public function test_quiz_core_calendar_provide_event_action_no_capability(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', ['shortname' => 'student']); // Enrol student. $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id)); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); // Remove the permission to attempt or review the quiz for the student role. $coursecontext = \context_course::instance($course->id); assign_capability('mod/quiz:reviewmyattempts', CAP_PROHIBIT, $studentrole->id, $coursecontext); assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $studentrole->id, $coursecontext); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Set current user to the student. $this->setUser($student); // Confirm null is returned. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory)); } public function test_quiz_core_calendar_provide_event_action_no_capability_for_user(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', ['shortname' => 'student']); // Enrol student. $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id)); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id]); // Remove the permission to attempt or review the quiz for the student role. $coursecontext = \context_course::instance($course->id); assign_capability('mod/quiz:reviewmyattempts', CAP_PROHIBIT, $studentrole->id, $coursecontext); assign_capability('mod/quiz:attempt', CAP_PROHIBIT, $studentrole->id, $coursecontext); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Confirm null is returned. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id)); } public function test_quiz_core_calendar_provide_event_action_already_finished(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', ['shortname' => 'student']); // Enrol student. $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id)); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'sumgrades' => 1]); // Add a question to the quiz. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $question = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); // Get the quiz object. $quizobj = quiz_settings::create($quiz->id, $student->id); // Create an attempt for the student in the quiz. $timenow = time(); $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id); $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj, $quba, $attempt); // Finish the attempt. $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submit($timenow, false); $attemptobj->process_grade_submission($timenow); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Set current user to the student. $this->setUser($student); // Confirm null is returned. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory)); } public function test_quiz_core_calendar_provide_event_action_already_finished_for_user(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', ['shortname' => 'student']); // Enrol student. $this->assertTrue($this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id)); // Create a quiz. $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'sumgrades' => 1]); // Add a question to the quiz. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $question = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); // Get the quiz object. $quizobj = quiz_settings::create($quiz->id, $student->id); // Create an attempt for the student in the quiz. $timenow = time(); $attempt = quiz_create_attempt($quizobj, 1, false, $timenow, false, $student->id); $quba = \question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); quiz_attempt_save_started($quizobj, $quba, $attempt); // Finish the attempt. $attemptobj = quiz_attempt::create($attempt->id); $attemptobj->process_submit($timenow, false); $attemptobj->process_grade_submission($timenow); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, QUIZ_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Confirm null is returned. $this->assertNull(mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id)); } public function test_quiz_core_calendar_provide_event_action_already_completed(): void { $this->resetAfterTest(); set_config('enablecompletion', 1); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]); $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id], ['completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS]); // Get some additional data. $cm = get_coursemodule_from_instance('quiz', $quiz->id); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory); // Ensure result was null. $this->assertNull($actionevent); } public function test_quiz_core_calendar_provide_event_action_already_completed_for_user(): void { $this->resetAfterTest(); set_config('enablecompletion', 1); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]); $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id], ['completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS]); // Enrol a student in the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Get some additional data. $cm = get_coursemodule_from_instance('quiz', $quiz->id); // Create a calendar event. $event = $this->create_action_event($course->id, $quiz->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed for the student. $completion = new \completion_info($course); $completion->set_module_viewed($cm, $student->id); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_quiz_core_calendar_provide_event_action($event, $factory, $student->id); // Ensure result was null. $this->assertNull($actionevent); } /** * Creates an action event. * * @param int $courseid * @param int $instanceid The quiz id. * @param string $eventtype The event type. eg. QUIZ_EVENT_TYPE_OPEN. * @return bool|calendar_event */ private function create_action_event($courseid, $instanceid, $eventtype) { $event = new \stdClass(); $event->name = 'Calendar event'; $event->modulename = 'quiz'; $event->courseid = $courseid; $event->instance = $instanceid; $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->eventtype = $eventtype; $event->timestart = time(); return \calendar_event::create($event); } /** * Test the callback responsible for returning the completion rule descriptions. * This function should work given either an instance of the module (cm_info), such as when checking the active rules, * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type. */ public function test_mod_quiz_completion_get_active_rule_descriptions(): void { $this->resetAfterTest(); $this->setAdminUser(); // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't. $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]); $quiz1 = $this->getDataGenerator()->create_module('quiz', [ 'course' => $course->id, 'completion' => 2, 'completionusegrade' => 1, 'completionpassgrade' => 1, 'completionattemptsexhausted' => 1, ]); $quiz2 = $this->getDataGenerator()->create_module('quiz', [ 'course' => $course->id, 'completion' => 2, 'completionusegrade' => 0 ]); $cm1 = \cm_info::create(get_coursemodule_from_instance('quiz', $quiz1->id)); $cm2 = \cm_info::create(get_coursemodule_from_instance('quiz', $quiz2->id)); // Data for the stdClass input type. // This type of input would occur when checking the default completion rules for an activity type, where we don't have // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info. $moddefaults = new \stdClass(); $moddefaults->customdata = ['customcompletionrules' => [ 'completionattemptsexhausted' => 1, ]]; $moddefaults->completion = 2; $activeruledescriptions = [ get_string('completionpassorattemptsexhausteddesc', 'quiz'), ]; $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($cm1), $activeruledescriptions); $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($cm2), []); $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions); $this->assertEquals(mod_quiz_get_completion_active_rule_descriptions(new \stdClass()), []); } /** * A user who does not have capabilities to add events to the calendar should be able to create a quiz. */ public function test_creation_with_no_calendar_capabilities(): void { $this->resetAfterTest(); $course = self::getDataGenerator()->create_course(); $context = \context_course::instance($course->id); $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher'); $roleid = self::getDataGenerator()->create_role(); self::getDataGenerator()->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); $generator = self::getDataGenerator()->get_plugin_generator('mod_quiz'); // Create an instance as a user without the calendar capabilities. $this->setUser($user); $time = time(); $params = [ 'course' => $course->id, 'timeopen' => $time + 200, 'timeclose' => $time + 2000, ]; $generator->create_instance($params); } /** * Data provider for summarise_response() test cases. * * @return array List of data sets (test cases) */ public static function mod_quiz_inplace_editable_provider(): array { return [ 'set to A1' => [1, 'A1'], 'set with HTML characters' => [2, 'A & & <-:'], 'set to integer' => [3, '3'], 'set to blank' => [4, ''], 'set with Unicode characters' => [1, 'L\'Aina Lluís^'], 'set with Unicode at the truncation point' => [1, '123456789012345碁'], 'set with HTML Char at the truncation point' => [1, '123456789012345>'], ]; } /** * Test customised and automated question numbering for a given slot number and customised value. * * @dataProvider mod_quiz_inplace_editable_provider * @param int $slotnumber * @param string $newvalue * @covers ::mod_quiz_inplace_editable */ public function test_mod_quiz_inplace_editable(int $slotnumber, string $newvalue): void { global $CFG; require_once($CFG->dirroot . '/lib/external/externallib.php'); $this->resetAfterTest(); $this->setAdminUser(); $course = self::getDataGenerator()->create_course(); $quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'sumgrades' => 1]); $cm = get_coursemodule_from_id('quiz', $quiz->cmid); // Add few questions to the quiz. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $question = $questiongenerator->create_question('truefalse', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); $question = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); $question = $questiongenerator->create_question('multichoice', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); $question = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]); quiz_add_quiz_question($question->id, $quiz); // Create the quiz object. $quizobj = new quiz_settings($quiz, $cm, $course); $structure = $quizobj->get_structure(); $slots = $structure->get_slots(); $this->assertEquals(4, count($slots)); $slotid = $structure->get_slot_id_for_slot($slotnumber); $inplaceeditable = mod_quiz_inplace_editable('slotdisplaynumber', $slotid, $newvalue); $result = \core_external::update_inplace_editable('mod_quiz', 'slotdisplaynumber', $slotid, $newvalue); $result = external_api::clean_returnvalue(\core_external::update_inplace_editable_returns(), $result); $this->assertEquals(count((array) $inplaceeditable), count($result)); $this->assertEquals($slotid, $result['itemid']); if ($newvalue === '' || is_null($newvalue)) { // Check against default. $this->assertEquals($slotnumber, $result['displayvalue']); $this->assertEquals($slotnumber, $result['value']); } else { // Check against the custom number. $this->assertEquals(s($newvalue), $result['displayvalue']); $this->assertEquals($newvalue, $result['value']); } } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/lti/tests/lib_test.php000064400000044007152267064440023727 0ustar00. /** * Unit tests for mod_lti lib * * @package mod_lti * @category external * @copyright 2015 Juan Leyva * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 3.0 */ namespace mod_lti; defined('MOODLE_INTERNAL') || die(); /** * Unit tests for mod_lti lib * * @package mod_lti * @category external * @copyright 2015 Juan Leyva * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 3.0 */ final class lib_test extends \advanced_testcase { /** * Prepares things before this test case is initialised * @return void */ public static function setUpBeforeClass(): void { global $CFG; require_once($CFG->dirroot . '/mod/lti/lib.php'); parent::setUpBeforeClass(); } /** * Test lti_view * @return void */ public function test_lti_view(): void { global $CFG; $CFG->enablecompletion = 1; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id), array('completion' => 2, 'completionview' => 1)); $context = \context_module::instance($lti->cmid); $cm = get_coursemodule_from_instance('lti', $lti->id); // Trigger and capture the event. $sink = $this->redirectEvents(); lti_view($lti, $course, $cm, $context); $events = $sink->get_events(); // 2 additional events thanks to completion. $this->assertCount(3, $events); $event = array_shift($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_lti\event\course_module_viewed', $event); $this->assertEquals($context, $event->get_context()); $moodleurl = new \moodle_url('/mod/lti/view.php', array('id' => $cm->id)); $this->assertEquals($moodleurl, $event->get_url()); $this->assertEventContextNotUsed($event); $this->assertNotEmpty($event->get_name()); // Check completion status. $completion = new \completion_info($course); $completiondata = $completion->get_data($cm); $this->assertEquals(1, $completiondata->completionstate); } /** * Test deleting LTI instance. */ public function test_lti_delete_instance(): void { $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(array()); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id)); $cm = get_coursemodule_from_instance('lti', $lti->id); // Must not throw notices. course_delete_module($cm->id); } public function test_lti_core_calendar_provide_event_action(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('view'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_lti_core_calendar_provide_event_action_as_non_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory); // Confirm the event is not shown at all. $this->assertNull($actionevent); } public function test_lti_core_calendar_provide_event_action_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id)); // Enrol a student in the course. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('view'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_lti_core_calendar_provide_event_action_already_completed(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Get some additional data. $cm = get_coursemodule_from_instance('lti', $lti->id); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory); // Ensure result was null. $this->assertNull($actionevent); } public function test_lti_core_calendar_provide_event_action_already_completed_as_non_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Get some additional data. $cm = get_coursemodule_from_instance('lti', $lti->id); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory); // Ensure result was null. $this->assertNull($actionevent); } public function test_lti_core_calendar_provide_event_action_already_completed_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $lti = $this->getDataGenerator()->create_module('lti', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Enrol 2 students in the course. $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Get some additional data. $cm = get_coursemodule_from_instance('lti', $lti->id); // Create a calendar event. $event = $this->create_action_event($course->id, $lti->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed for $student1. $completion = new \completion_info($course); $completion->set_module_viewed($cm, $student1->id); // Now, log in as $student2. $this->setUser($student2); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for $student1. $actionevent = mod_lti_core_calendar_provide_event_action($event, $factory, $student1->id); // Ensure result was null. $this->assertNull($actionevent); } /** * Creates an action event. * * @param int $courseid The course id. * @param int $instanceid The instance id. * @param string $eventtype The event type. * @return bool|calendar_event */ private function create_action_event($courseid, $instanceid, $eventtype) { $event = new \stdClass(); $event->name = 'Calendar event'; $event->modulename = 'lti'; $event->courseid = $courseid; $event->instance = $instanceid; $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->eventtype = $eventtype; $event->timestart = time(); return \calendar_event::create($event); } /** * Test verifying the output of the lti_get_course_content_items and lti_get_all_content_items callbacks. */ public function test_content_item_callbacks(): void { $this->resetAfterTest(); global $DB, $CFG; require_once($CFG->dirroot . '/mod/lti/locallib.php'); $admin = get_admin(); $time = time(); $course = $this->getDataGenerator()->create_course(); $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); $course2 = $this->getDataGenerator()->create_course(); $teacher2 = $this->getDataGenerator()->create_and_enrol($course2, 'editingteacher'); // Create some preconfigured tools. $sitetoolrecord = (object) [ 'name' => 'Site level tool which is available in the activity chooser', 'baseurl' => 'http://example.com', 'createdby' => $admin->id, 'course' => SITEID, 'ltiversion' => 'LTI-1p0', 'timecreated' => $time, 'timemodified' => $time, 'state' => LTI_TOOL_STATE_CONFIGURED, 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER ]; $sitetoolrecordnonchooser = (object) [ 'name' => 'Site level tool which is NOT available in the course activity chooser', 'baseurl' => 'http://example2.com', 'createdby' => $admin->id, 'course' => SITEID, 'ltiversion' => 'LTI-1p0', 'timecreated' => $time, 'timemodified' => $time, 'state' => LTI_TOOL_STATE_CONFIGURED, 'coursevisible' => LTI_COURSEVISIBLE_PRECONFIGURED ]; $course1toolrecord = (object) [ 'name' => 'Course created tool which is available in the activity chooser', 'baseurl' => 'http://example3.com', 'createdby' => $teacher->id, 'course' => $course->id, 'ltiversion' => 'LTI-1p0', 'timecreated' => $time, 'timemodified' => $time, 'state' => LTI_TOOL_STATE_CONFIGURED, 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER ]; $course2toolrecord = (object) [ 'name' => 'Course created tool which is available in the activity chooser', 'baseurl' => 'http://example4.com', 'createdby' => $teacher2->id, 'course' => $course2->id, 'ltiversion' => 'LTI-1p0', 'timecreated' => $time, 'timemodified' => $time, 'state' => LTI_TOOL_STATE_CONFIGURED, 'coursevisible' => LTI_COURSEVISIBLE_ACTIVITYCHOOSER ]; $tool1id = $DB->insert_record('lti_types', $sitetoolrecord); $tool2id = $DB->insert_record('lti_types', $sitetoolrecordnonchooser); $tool3id = $DB->insert_record('lti_types', $course1toolrecord); $tool4id = $DB->insert_record('lti_types', $course2toolrecord); $sitetoolrecord->id = $tool1id; $sitetoolrecordnonchooser->id = $tool2id; $course1toolrecord->id = $tool3id; $course2toolrecord->id = $tool4id; $defaultmodulecontentitem = new \core_course\local\entity\content_item( '1', 'default module content item', new \core_course\local\entity\string_title('Content item title'), new \moodle_url(''), 'icon', 'Description of the module', MOD_ARCHETYPE_OTHER, 'mod_lti', MOD_PURPOSE_CONTENT ); // The lti_get_lti_types_by_course method (used by the callbacks) assumes the global user. $this->setUser($teacher); // Teacher in course1 should be able to see the site preconfigured tool and the tool created in course1. $courseitems = lti_get_course_content_items($defaultmodulecontentitem, $teacher, $course); $this->assertCount(2, $courseitems); $ids = []; foreach ($courseitems as $item) { $ids[] = $item->get_id(); } $this->assertContains($sitetoolrecord->id + 1, $ids); $this->assertContains($course1toolrecord->id + 1, $ids); $this->assertNotContains($sitetoolrecordnonchooser->id + 1, $ids); // The content items for teacher2 in course2 include the site preconfigured tool and the tool created in course2. $this->setUser($teacher2); $course2items = lti_get_course_content_items($defaultmodulecontentitem, $teacher2, $course2); $this->assertCount(2, $course2items); $ids = []; foreach ($course2items as $item) { $ids[] = $item->get_id(); } $this->assertContains($sitetoolrecord->id + 1, $ids); $this->assertContains($course2toolrecord->id + 1, $ids); $this->assertNotContains($sitetoolrecordnonchooser->id + 1, $ids); // Removing the capability to use preconfigured (site or course level) tools, should result in no content items. $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); assign_capability('mod/lti:addpreconfiguredinstance', CAP_PROHIBIT, $teacherrole->id, \core\context\course::instance($course2->id)); $course2items = lti_get_course_content_items($defaultmodulecontentitem, $teacher2, $course2); $this->assertCount(0, $course2items); // When fetching all content items, we expect to see all items available in activity choosers (in any course). $this->setAdminUser(); $allitems = mod_lti_get_all_content_items($defaultmodulecontentitem); $this->assertCount(3, $allitems); $ids = []; foreach ($allitems as $item) { $ids[] = $item->get_id(); } $this->assertContains($sitetoolrecord->id + 1, $ids); $this->assertContains($course1toolrecord->id + 1, $ids); $this->assertContains($course2toolrecord->id + 1, $ids); $this->assertNotContains($sitetoolrecordnonchooser->id + 1, $ids); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/wiki/tests/lib_test.php000064400000123403152267065140024076 0ustar00. /** * Unit tests for mod_wiki lib * * @package mod_wiki * @category external * @copyright 2015 Dani Palou * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 3.1 */ namespace mod_wiki; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/wiki/lib.php'); require_once($CFG->dirroot . '/mod/wiki/locallib.php'); require_once($CFG->libdir . '/completionlib.php'); /** * Unit tests for mod_wiki lib * * @package mod_wiki * @category external * @copyright 2015 Dani Palou * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 3.1 */ final class lib_test extends \advanced_testcase { /** * Test wiki_view. * * @return void */ public function test_wiki_view(): void { global $CFG; $CFG->enablecompletion = COMPLETION_ENABLED; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => COMPLETION_ENABLED)); $options = array('completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => COMPLETION_VIEW_REQUIRED); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id), $options); $context = \context_module::instance($wiki->cmid); $cm = get_coursemodule_from_instance('wiki', $wiki->id); // Trigger and capture the event. $sink = $this->redirectEvents(); wiki_view($wiki, $course, $cm, $context); $events = $sink->get_events(); // 2 additional events thanks to completion. $this->assertCount(3, $events); $event = array_shift($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_wiki\event\course_module_viewed', $event); $this->assertEquals($context, $event->get_context()); $moodleurl = new \moodle_url('/mod/wiki/view.php', array('id' => $cm->id)); $this->assertEquals($moodleurl, $event->get_url()); $this->assertEventContextNotUsed($event); $this->assertNotEmpty($event->get_name()); // Check completion status. $completion = new \completion_info($course); $completiondata = $completion->get_data($cm); $this->assertEquals(1, $completiondata->completionstate); } /** * Test wiki_page_view. * * @return void */ public function test_wiki_page_view(): void { global $CFG; $CFG->enablecompletion = COMPLETION_ENABLED; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => COMPLETION_ENABLED)); $options = array('completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => COMPLETION_VIEW_REQUIRED); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id), $options); $context = \context_module::instance($wiki->cmid); $cm = get_coursemodule_from_instance('wiki', $wiki->id); $firstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($wiki); // Trigger and capture the event. $sink = $this->redirectEvents(); wiki_page_view($wiki, $firstpage, $course, $cm, $context); $events = $sink->get_events(); // 2 additional events thanks to completion. $this->assertCount(3, $events); $event = array_shift($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_wiki\event\page_viewed', $event); $this->assertEquals($context, $event->get_context()); $pageurl = new \moodle_url('/mod/wiki/view.php', array('pageid' => $firstpage->id)); $this->assertEquals($pageurl, $event->get_url()); $this->assertEventContextNotUsed($event); $this->assertNotEmpty($event->get_name()); // Check completion status. $completion = new \completion_info($course); $completiondata = $completion->get_data($cm); $this->assertEquals(1, $completiondata->completionstate); } /** * Test wiki_user_can_edit without groups. * * @return void */ public function test_wiki_user_can_edit(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $indwiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'wikimode' => 'individual')); $colwiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'wikimode' => 'collaborative')); // Create users. $student = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Simulate collaborative subwiki. $swcol = new \stdClass(); $swcol->id = -1; $swcol->wikiid = $colwiki->id; $swcol->groupid = 0; $swcol->userid = 0; // Simulate individual subwikis (1 per user). $swindstudent = clone($swcol); $swindstudent->wikiid = $indwiki->id; $swindstudent->userid = $student->id; $swindteacher = clone($swindstudent); $swindteacher->userid = $teacher->id; $this->setUser($student); // Check that the student can edit the collaborative subwiki. $this->assertTrue(wiki_user_can_edit($swcol)); // Check that the student can edit his individual subwiki. $this->assertTrue(wiki_user_can_edit($swindstudent)); // Check that the student cannot edit teacher's individual subwiki. $this->assertFalse(wiki_user_can_edit($swindteacher)); // Now test as a teacher. $this->setUser($teacher); // Check that the teacher can edit the collaborative subwiki. $this->assertTrue(wiki_user_can_edit($swcol)); // Check that the teacher can edit his individual subwiki. $this->assertTrue(wiki_user_can_edit($swindteacher)); // Check that the teacher can edit student's individual subwiki. $this->assertTrue(wiki_user_can_edit($swindstudent)); } /** * Test wiki_user_can_edit using collaborative wikis with groups. * * @return void */ public function test_wiki_user_can_edit_with_groups_collaborative(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $wikisepcol = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS, 'wikimode' => 'collaborative')); $wikiviscol = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS, 'wikimode' => 'collaborative')); // Create users. $student = self::getDataGenerator()->create_user(); $student2 = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Create groups. $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student->id, 'groupid' => $group1->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group1->id)); $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group2->id)); // Simulate all the possible subwikis. // Subwikis in collaborative wikis: 1 subwiki per group + 1 subwiki for all participants. $swsepcolg1 = new \stdClass(); $swsepcolg1->id = -1; $swsepcolg1->wikiid = $wikisepcol->id; $swsepcolg1->groupid = $group1->id; $swsepcolg1->userid = 0; $swsepcolg2 = clone($swsepcolg1); $swsepcolg2->groupid = $group2->id; $swsepcolallparts = clone($swsepcolg1); // All participants. $swsepcolallparts->groupid = 0; $swviscolg1 = clone($swsepcolg1); $swviscolg1->wikiid = $wikiviscol->id; $swviscolg2 = clone($swviscolg1); $swviscolg2->groupid = $group2->id; $swviscolallparts = clone($swviscolg1); // All participants. $swviscolallparts->groupid = 0; $this->setUser($student); // Check that the student can edit his group's subwiki both in separate and visible groups. $this->assertTrue(wiki_user_can_edit($swsepcolg1)); $this->assertTrue(wiki_user_can_edit($swviscolg1)); // Check that the student cannot edit subwiki from group 2 both in separate and visible groups. $this->assertFalse(wiki_user_can_edit($swsepcolg2)); $this->assertFalse(wiki_user_can_edit($swviscolg2)); // Now test as student 2. $this->setUser($student2); // Check that the student 2 can edit subwikis from both groups both in separate and visible groups. $this->assertTrue(wiki_user_can_edit($swsepcolg1)); $this->assertTrue(wiki_user_can_edit($swviscolg1)); $this->assertTrue(wiki_user_can_edit($swsepcolg2)); $this->assertTrue(wiki_user_can_edit($swviscolg2)); // Check that the student 2 cannot edit subwikis from all participants. $this->assertFalse(wiki_user_can_edit($swsepcolallparts)); $this->assertFalse(wiki_user_can_edit($swviscolallparts)); // Now test it as a teacher. $this->setUser($teacher); // Check that teacher can edit all subwikis. $this->assertTrue(wiki_user_can_edit($swsepcolg1)); $this->assertTrue(wiki_user_can_edit($swviscolg1)); $this->assertTrue(wiki_user_can_edit($swsepcolg2)); $this->assertTrue(wiki_user_can_edit($swviscolg2)); $this->assertTrue(wiki_user_can_edit($swsepcolallparts)); $this->assertTrue(wiki_user_can_edit($swviscolallparts)); } /** * Test wiki_user_can_edit using individual wikis with groups. * * @return void */ public function test_wiki_user_can_edit_with_groups_individual(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $wikisepind = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS, 'wikimode' => 'individual')); $wikivisind = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS, 'wikimode' => 'individual')); // Create users. $student = self::getDataGenerator()->create_user(); $student2 = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Create groups. $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student->id, 'groupid' => $group1->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group1->id)); $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group2->id)); // Simulate all the possible subwikis. // Subwikis in collaborative wikis: 1 subwiki per group + 1 subwiki for all participants. $swsepindg1s1 = new \stdClass(); $swsepindg1s1->id = -1; $swsepindg1s1->wikiid = $wikisepind->id; $swsepindg1s1->groupid = $group1->id; $swsepindg1s1->userid = $student->id; $swsepindg1s2 = clone($swsepindg1s1); $swsepindg1s2->userid = $student2->id; $swsepindg2s2 = clone($swsepindg1s2); $swsepindg2s2->groupid = $group2->id; $swsepindteacher = clone($swsepindg1s1); $swsepindteacher->userid = $teacher->id; $swsepindteacher->groupid = 0; $swvisindg1s1 = clone($swsepindg1s1); $swvisindg1s1->wikiid = $wikivisind->id; $swvisindg1s2 = clone($swvisindg1s1); $swvisindg1s2->userid = $student2->id; $swvisindg2s2 = clone($swvisindg1s2); $swvisindg2s2->groupid = $group2->id; $swvisindteacher = clone($swvisindg1s1); $swvisindteacher->userid = $teacher->id; $swvisindteacher->groupid = 0; $this->setUser($student); // Check that the student can edit his subwiki both in separate and visible groups. $this->assertTrue(wiki_user_can_edit($swsepindg1s1)); $this->assertTrue(wiki_user_can_edit($swvisindg1s1)); // Check that the student cannot edit subwikis from another user even if he belongs to his group. $this->assertFalse(wiki_user_can_edit($swsepindg1s2)); $this->assertFalse(wiki_user_can_edit($swvisindg1s2)); // Now test as student 2. $this->setUser($student2); // Check that the student 2 can edit his subwikis from both groups both in separate and visible groups. $this->assertTrue(wiki_user_can_edit($swsepindg1s2)); $this->assertTrue(wiki_user_can_edit($swvisindg1s2)); $this->assertTrue(wiki_user_can_edit($swsepindg2s2)); $this->assertTrue(wiki_user_can_edit($swvisindg2s2)); // Now test it as a teacher. $this->setUser($teacher); // Check that teacher can edit all subwikis. $this->assertTrue(wiki_user_can_edit($swsepindg1s1)); $this->assertTrue(wiki_user_can_edit($swsepindg1s2)); $this->assertTrue(wiki_user_can_edit($swsepindg2s2)); $this->assertTrue(wiki_user_can_edit($swsepindteacher)); $this->assertTrue(wiki_user_can_edit($swvisindg1s1)); $this->assertTrue(wiki_user_can_edit($swvisindg1s2)); $this->assertTrue(wiki_user_can_edit($swvisindg2s2)); $this->assertTrue(wiki_user_can_edit($swvisindteacher)); } /** * Test wiki_get_visible_subwikis without groups. * * @return void */ public function test_wiki_get_visible_subwikis_without_groups(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $indwiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'wikimode' => 'individual')); $colwiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'wikimode' => 'collaborative')); // Create users. $student = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); $this->setUser($student); // Check that not passing a wiki returns empty array. $result = wiki_get_visible_subwikis(null); $this->assertEquals(array(), $result); // Check that the student can get the only subwiki from the collaborative wiki. $expectedsubwikis = array(); $expectedsubwiki = new \stdClass(); $expectedsubwiki->id = -1; // We haven't created any page so the subwiki hasn't been created. $expectedsubwiki->wikiid = $colwiki->id; $expectedsubwiki->groupid = 0; $expectedsubwiki->userid = 0; $expectedsubwikis[] = $expectedsubwiki; $result = wiki_get_visible_subwikis($colwiki); $this->assertEquals($expectedsubwikis, $result); // Create a page now so the subwiki is created. $colfirstpage = $this->getDataGenerator()->get_plugin_generator('mod_wiki')->create_first_page($colwiki); // Call the function again, now we expect to have a subwiki ID. $expectedsubwikis[0]->id = $colfirstpage->subwikiid; $result = wiki_get_visible_subwikis($colwiki); $this->assertEquals($expectedsubwikis, $result); // Check that the teacher can see it too. $this->setUser($teacher); $result = wiki_get_visible_subwikis($colwiki); $this->assertEquals($expectedsubwikis, $result); // Check that the student can only see his subwiki in the individual wiki. $this->setUser($student); $expectedsubwikis[0]->id = -1; $expectedsubwikis[0]->wikiid = $indwiki->id; $expectedsubwikis[0]->userid = $student->id; $result = wiki_get_visible_subwikis($indwiki); $this->assertEquals($expectedsubwikis, $result); // Check that the teacher can see his subwiki and the student subwiki in the individual wiki. $this->setUser($teacher); $teachersubwiki = new \stdClass(); $teachersubwiki->id = -1; $teachersubwiki->wikiid = $indwiki->id; $teachersubwiki->groupid = 0; $teachersubwiki->userid = $teacher->id; $expectedsubwikis[] = $teachersubwiki; $result = wiki_get_visible_subwikis($indwiki); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); // Compare without order. } /** * Test wiki_get_visible_subwikis using collaborative wikis with groups. * * @return void */ public function test_wiki_get_visible_subwikis_with_groups_collaborative(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $wikisepcol = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS, 'wikimode' => 'collaborative')); $wikiviscol = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS, 'wikimode' => 'collaborative')); // Create users. $student = self::getDataGenerator()->create_user(); $student2 = self::getDataGenerator()->create_user(); $student3 = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student3->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Create groups. $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student->id, 'groupid' => $group1->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group1->id)); $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group2->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student3->id, 'groupid' => $group2->id)); $this->setUser($student); // Create all the possible subwikis. We haven't created any page so ids will be -1. // Subwikis in collaborative wikis: 1 subwiki per group + 1 subwiki for all participants. $swsepcolg1 = new \stdClass(); $swsepcolg1->id = -1; $swsepcolg1->wikiid = $wikisepcol->id; $swsepcolg1->groupid = $group1->id; $swsepcolg1->userid = 0; $swsepcolg2 = clone($swsepcolg1); $swsepcolg2->groupid = $group2->id; $swsepcolallparts = clone($swsepcolg1); // All participants. $swsepcolallparts->groupid = 0; $swviscolg1 = clone($swsepcolg1); $swviscolg1->wikiid = $wikiviscol->id; $swviscolg2 = clone($swviscolg1); $swviscolg2->groupid = $group2->id; $swviscolallparts = clone($swviscolg1); // All participants. $swviscolallparts->groupid = 0; // Check that the student can get only the subwiki from his group in collaborative wiki with separate groups. $expectedsubwikis = array($swsepcolg1); $result = wiki_get_visible_subwikis($wikisepcol); $this->assertEquals($expectedsubwikis, $result); // Check that he can get subwikis from both groups in collaborative wiki with visible groups, and also all participants. $expectedsubwikis = array($swviscolallparts, $swviscolg1, $swviscolg2); $result = wiki_get_visible_subwikis($wikiviscol); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); // Now test it as a teacher. No need to check visible groups wikis because the result is the same as student. $this->setUser($teacher); // Check that he can get the subwikis from all the groups in collaborative wiki with separate groups. $expectedsubwikis = array($swsepcolg1, $swsepcolg2, $swsepcolallparts); $result = wiki_get_visible_subwikis($wikisepcol); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); } /** * Test wiki_get_visible_subwikis using individual wikis with groups. * * @return void */ public function test_wiki_get_visible_subwikis_with_groups_individual(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $course = $this->getDataGenerator()->create_course(); $wikisepind = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS, 'wikimode' => 'individual')); $wikivisind = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS, 'wikimode' => 'individual')); // Create users. $student = self::getDataGenerator()->create_user(); $student2 = self::getDataGenerator()->create_user(); $student3 = self::getDataGenerator()->create_user(); $teacher = self::getDataGenerator()->create_user(); // Users enrolments. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student3->id, $course->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual'); // Create groups. $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student->id, 'groupid' => $group1->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group1->id)); $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student2->id, 'groupid' => $group2->id)); $this->getDataGenerator()->create_group_member(array('userid' => $student3->id, 'groupid' => $group2->id)); $this->setUser($student); // Create all the possible subwikis to be returned. We haven't created any page so ids will be -1. // Subwikis in individual wikis: 1 subwiki per user and group. If user doesn't belong to any group then groupid is 0. $swsepindg1s1 = new \stdClass(); $swsepindg1s1->id = -1; $swsepindg1s1->wikiid = $wikisepind->id; $swsepindg1s1->groupid = $group1->id; $swsepindg1s1->userid = $student->id; $swsepindg1s2 = clone($swsepindg1s1); $swsepindg1s2->userid = $student2->id; $swsepindg2s2 = clone($swsepindg1s2); $swsepindg2s2->groupid = $group2->id; $swsepindg2s3 = clone($swsepindg1s1); $swsepindg2s3->userid = $student3->id; $swsepindg2s3->groupid = $group2->id; $swsepindteacher = clone($swsepindg1s1); $swsepindteacher->userid = $teacher->id; $swsepindteacher->groupid = 0; $swvisindg1s1 = clone($swsepindg1s1); $swvisindg1s1->wikiid = $wikivisind->id; $swvisindg1s2 = clone($swvisindg1s1); $swvisindg1s2->userid = $student2->id; $swvisindg2s2 = clone($swvisindg1s2); $swvisindg2s2->groupid = $group2->id; $swvisindg2s3 = clone($swvisindg1s1); $swvisindg2s3->userid = $student3->id; $swvisindg2s3->groupid = $group2->id; $swvisindteacher = clone($swvisindg1s1); $swvisindteacher->userid = $teacher->id; $swvisindteacher->groupid = 0; // Check that student can get the subwikis from his group in individual wiki with separate groups. $expectedsubwikis = array($swsepindg1s1, $swsepindg1s2); $result = wiki_get_visible_subwikis($wikisepind); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); // Check that he can get subwikis from all users and groups in individual wiki with visible groups. $expectedsubwikis = array($swvisindg1s1, $swvisindg1s2, $swvisindg2s2, $swvisindg2s3, $swvisindteacher); $result = wiki_get_visible_subwikis($wikivisind); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); // Now test it as a teacher. No need to check visible groups wikis because the result is the same as student. $this->setUser($teacher); // Check that teacher can get the subwikis from all the groups in individual wiki with separate groups. $expectedsubwikis = array($swsepindg1s1, $swsepindg1s2, $swsepindg2s2, $swsepindg2s3, $swsepindteacher); $result = wiki_get_visible_subwikis($wikisepind); $this->assertEqualsCanonicalizing($expectedsubwikis, $result); } public function test_mod_wiki_get_tagged_pages(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $wikigenerator = $this->getDataGenerator()->get_plugin_generator('mod_wiki'); $course3 = $this->getDataGenerator()->create_course(); $course2 = $this->getDataGenerator()->create_course(); $course1 = $this->getDataGenerator()->create_course(); $wiki1 = $this->getDataGenerator()->create_module('wiki', array('course' => $course1->id)); $wiki2 = $this->getDataGenerator()->create_module('wiki', array('course' => $course2->id)); $wiki3 = $this->getDataGenerator()->create_module('wiki', array('course' => $course3->id)); $page11 = $wikigenerator->create_content($wiki1, array('tags' => array('Cats', 'Dogs'))); $page12 = $wikigenerator->create_content($wiki1, array('tags' => array('Cats', 'mice'))); $page13 = $wikigenerator->create_content($wiki1, array('tags' => array('Cats'))); $page14 = $wikigenerator->create_content($wiki1); $page15 = $wikigenerator->create_content($wiki1, array('tags' => array('Cats'))); $page21 = $wikigenerator->create_content($wiki2, array('tags' => array('Cats'))); $page22 = $wikigenerator->create_content($wiki2, array('tags' => array('Cats', 'Dogs'))); $page23 = $wikigenerator->create_content($wiki2, array('tags' => array('mice', 'Cats'))); $page31 = $wikigenerator->create_content($wiki3, array('tags' => array('mice', 'Cats'))); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_wiki_get_tagged_pages($tag, /*$exclusivemode = */false, /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$page = */0); $this->assertMatchesRegularExpression('/'.$page11->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page12->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page13->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page14->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page15->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page21->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page22->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page23->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page31->title.'/', $res->content); $this->assertEmpty($res->prevpageurl); $this->assertNotEmpty($res->nextpageurl); $res = mod_wiki_get_tagged_pages($tag, /*$exclusivemode = */false, /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$page = */1); $this->assertDoesNotMatchRegularExpression('/'.$page11->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page12->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page13->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page14->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page15->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page21->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page22->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page23->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page31->title.'/', $res->content); $this->assertNotEmpty($res->prevpageurl); $this->assertEmpty($res->nextpageurl); // Create and enrol a user. $student = self::getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); $this->setUser($student); \core_tag_index_builder::reset_caches(); // User can not see pages in course 3 because he is not enrolled. $res = mod_wiki_get_tagged_pages($tag, /*$exclusivemode = */false, /*$fromctx = */0, /*$ctx = */0, /*$rec = */1, /*$page = */1); $this->assertMatchesRegularExpression('/'.$page22->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page23->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page31->title.'/', $res->content); // User can search wiki pages inside a course. $coursecontext = \context_course::instance($course1->id); $res = mod_wiki_get_tagged_pages($tag, /*$exclusivemode = */false, /*$fromctx = */0, /*$ctx = */$coursecontext->id, /*$rec = */1, /*$page = */0); $this->assertMatchesRegularExpression('/'.$page11->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page12->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page13->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page14->title.'/', $res->content); $this->assertMatchesRegularExpression('/'.$page15->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page21->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page22->title.'/', $res->content); $this->assertDoesNotMatchRegularExpression('/'.$page23->title.'/', $res->content); $this->assertEmpty($res->nextpageurl); } public function test_wiki_core_calendar_provide_event_action(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $wiki->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_wiki_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('view'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_wiki_core_calendar_provide_event_action_for_non_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $wiki->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_wiki_core_calendar_provide_event_action($event, $factory); // Confirm the event is not shown at all. $this->assertNull($actionevent); } public function test_wiki_core_calendar_provide_event_action_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create the activity. $course = $this->getDataGenerator()->create_course(); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id)); $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a calendar event. $event = $this->create_action_event($course->id, $wiki->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Now log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_wiki_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('view'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_wiki_core_calendar_provide_event_action_already_completed(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Get some additional data. $cm = get_coursemodule_from_instance('wiki', $wiki->id); // Create a calendar event. $event = $this->create_action_event($course->id, $wiki->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed. $completion = new \completion_info($course); $completion->set_module_viewed($cm); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_wiki_core_calendar_provide_event_action($event, $factory); // Ensure result was null. $this->assertNull($actionevent); } public function test_wiki_core_calendar_provide_event_action_already_completed_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; // Create the activity. $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $course->id), array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS)); // Create 2 students and enrol them into the course. $student1 = $this->getDataGenerator()->create_and_enrol($course, 'student'); $student2 = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Get some additional data. $cm = get_coursemodule_from_instance('wiki', $wiki->id); // Create a calendar event. $event = $this->create_action_event($course->id, $wiki->id, \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED); // Mark the activity as completed for the $student1. $completion = new \completion_info($course); $completion->set_module_viewed($cm, $student1->id); // Now log in as $student2. $this->setUser($student2); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for $student1. $actionevent = mod_wiki_core_calendar_provide_event_action($event, $factory, $student1->id); // Ensure result was null. $this->assertNull($actionevent); } /** * Creates an action event. * * @param int $courseid The course id. * @param int $instanceid The instance id. * @param string $eventtype The event type. * @return bool|calendar_event */ private function create_action_event($courseid, $instanceid, $eventtype) { $event = new \stdClass(); $event->name = 'Calendar event'; $event->modulename = 'wiki'; $event->courseid = $courseid; $event->instance = $instanceid; $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->eventtype = $eventtype; $event->timestart = time(); return \calendar_event::create($event); } } home/smkb8269/public_html/lms.smk-almanshuriyah.sch.id/mod/data/tests/lib_test.php000064400000256646152267077070024071 0ustar00. /** * Unit tests for lib.php * * @package mod_data * @category phpunit * @copyright 2013 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace mod_data; use stdClass; defined('MOODLE_INTERNAL') || die(); global $CFG; require_once($CFG->dirroot . '/mod/data/lib.php'); /** * Unit tests for lib.php * * @package mod_data * @copyright 2013 Adrian Greeve * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class lib_test extends \advanced_testcase { /** * @var moodle_database */ protected $DB = null; /** * Tear Down to reset DB. */ public function tearDown(): void { global $DB; if (isset($this->DB)) { $DB = $this->DB; $this->DB = null; } parent::tearDown(); } /** * Confirms that completionentries is working * Sets it to 1, confirms that * it is not complete. Inserts a record and * confirms that it is complete. */ public function test_data_completion(): void { global $DB, $CFG; $this->resetAfterTest(); $this->setAdminUser(); $CFG->enablecompletion = 1; $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1)); $record = new \stdClass(); $record->course = $course->id; $record->name = "Mod data completion test"; $record->intro = "Some intro of some sort"; $record->completionentries = "1"; /* completion=2 means Show activity commplete when condition is met and completionentries means 1 record is * required for the activity to be considered complete */ $module = $this->getDataGenerator()->create_module('data', $record, array('completion' => 2, 'completionentries' => 1)); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); $completion = new \completion_info($course); $completiondata = $completion->get_data($cm, true, 0); /* Confirm it is not complete as there are no entries */ $this->assertNotEquals(1, $completiondata->completionstate); $field = data_get_field_new('text', $module); $fielddetail = new \stdClass(); $fielddetail->d = $module->id; $fielddetail->mode = 'add'; $fielddetail->type = 'text'; $fielddetail->sesskey = sesskey(); $fielddetail->name = 'Name'; $fielddetail->description = 'Some name'; $field->define_field($fielddetail); $field->insert_field(); $recordid = data_add_record($module); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid; $datacontent['content'] = 'Asterix'; $contentid = $DB->insert_record('data_content', $datacontent); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); $completion = new \completion_info($course); $completiondata = $completion->get_data($cm); /* Confirm it is complete because it has 1 entry */ $this->assertEquals(1, $completiondata->completionstate); } public function test_data_delete_record(): void { global $DB; $this->resetAfterTest(); // Create a record for deleting. $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $record = new \stdClass(); $record->course = $course->id; $record->name = "Mod data delete test"; $record->intro = "Some intro of some sort"; $module = $this->getDataGenerator()->create_module('data', $record); $field = data_get_field_new('text', $module); $fielddetail = new \stdClass(); $fielddetail->d = $module->id; $fielddetail->mode = 'add'; $fielddetail->type = 'text'; $fielddetail->sesskey = sesskey(); $fielddetail->name = 'Name'; $fielddetail->description = 'Some name'; $field->define_field($fielddetail); $field->insert_field(); $recordid = data_add_record($module); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid; $datacontent['content'] = 'Asterix'; $contentid = $DB->insert_record('data_content', $datacontent); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); // Check to make sure that we have a database record. $data = $DB->get_records('data', array('id' => $module->id)); $this->assertEquals(1, count($data)); $datacontent = $DB->get_records('data_content', array('id' => $contentid)); $this->assertEquals(1, count($datacontent)); $datafields = $DB->get_records('data_fields', array('id' => $field->field->id)); $this->assertEquals(1, count($datafields)); $datarecords = $DB->get_records('data_records', array('id' => $recordid)); $this->assertEquals(1, count($datarecords)); // Test to see if a failed delete returns false. $result = data_delete_record(8798, $module, $course->id, $cm->id); $this->assertFalse($result); // Delete the record. $result = data_delete_record($recordid, $module, $course->id, $cm->id); // Check that all of the record is gone. $datacontent = $DB->get_records('data_content', array('id' => $contentid)); $this->assertEquals(0, count($datacontent)); $datarecords = $DB->get_records('data_records', array('id' => $recordid)); $this->assertEquals(0, count($datarecords)); // Make sure the function returns true on a successful deletion. $this->assertTrue($result); } /** * Test comment_created event. */ public function test_data_comment_created_event(): void { global $CFG, $DB; require_once($CFG->dirroot . '/comment/lib.php'); $this->resetAfterTest(); // Create a record for deleting. $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $record = new \stdClass(); $record->course = $course->id; $record->name = "Mod data delete test"; $record->intro = "Some intro of some sort"; $record->comments = 1; $module = $this->getDataGenerator()->create_module('data', $record); $field = data_get_field_new('text', $module); $fielddetail = new \stdClass(); $fielddetail->name = 'Name'; $fielddetail->description = 'Some name'; $field->define_field($fielddetail); $field->insert_field(); $recordid = data_add_record($module); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid; $datacontent['content'] = 'Asterix'; $contentid = $DB->insert_record('data_content', $datacontent); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); $context = \context_module::instance($module->cmid); $cmt = new \stdClass(); $cmt->context = $context; $cmt->course = $course; $cmt->cm = $cm; $cmt->area = 'database_entry'; $cmt->itemid = $recordid; $cmt->showcount = true; $cmt->component = 'mod_data'; $comment = new \comment($cmt); // Triggering and capturing the event. $sink = $this->redirectEvents(); $comment->add('New comment'); $events = $sink->get_events(); $this->assertCount(1, $events); $event = reset($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_data\event\comment_created', $event); $this->assertEquals($context, $event->get_context()); $url = new \moodle_url('/mod/data/view.php', array('id' => $cm->id)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } /** * Test comment_deleted event. */ public function test_data_comment_deleted_event(): void { global $CFG, $DB; require_once($CFG->dirroot . '/comment/lib.php'); $this->resetAfterTest(); // Create a record for deleting. $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $record = new \stdClass(); $record->course = $course->id; $record->name = "Mod data delete test"; $record->intro = "Some intro of some sort"; $record->comments = 1; $module = $this->getDataGenerator()->create_module('data', $record); $field = data_get_field_new('text', $module); $fielddetail = new \stdClass(); $fielddetail->name = 'Name'; $fielddetail->description = 'Some name'; $field->define_field($fielddetail); $field->insert_field(); $recordid = data_add_record($module); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid; $datacontent['content'] = 'Asterix'; $contentid = $DB->insert_record('data_content', $datacontent); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); $context = \context_module::instance($module->cmid); $cmt = new \stdClass(); $cmt->context = $context; $cmt->course = $course; $cmt->cm = $cm; $cmt->area = 'database_entry'; $cmt->itemid = $recordid; $cmt->showcount = true; $cmt->component = 'mod_data'; $comment = new \comment($cmt); $newcomment = $comment->add('New comment 1'); // Triggering and capturing the event. $sink = $this->redirectEvents(); $comment->delete($newcomment->id); $events = $sink->get_events(); $this->assertCount(1, $events); $event = reset($events); // Checking that the event contains the expected values. $this->assertInstanceOf('\mod_data\event\comment_deleted', $event); $this->assertEquals($context, $event->get_context()); $url = new \moodle_url('/mod/data/view.php', array('id' => $module->cmid)); $this->assertEquals($url, $event->get_url()); $this->assertEventContextNotUsed($event); } /** * Checks that data_user_can_manage_entry will return true if the user * has the mod/data:manageentries capability. */ public function test_data_user_can_manage_entry_return_true_with_capability(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); $this->setUser($user); assign_capability('mod/data:manageentries', CAP_ALLOW, $roleid, $context); $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 'data_user_can_manage_entry() returns true if the user has mod/data:manageentries capability'); } /** * Checks that data_user_can_manage_entry will return false if the data * is set to readonly. */ public function test_data_user_can_manage_entry_return_false_readonly(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); // Causes readonly mode to be enabled. $data = new \stdClass(); $now = time(); // Add a small margin around the periods to prevent errors with slow tests. $data->timeviewfrom = $now - 1; $data->timeviewto = $now + 5; $this->assertFalse(data_user_can_manage_entry($record, $data, $context), 'data_user_can_manage_entry() returns false if the data is read only'); } /** * Checks that data_user_can_manage_entry will return false if the record * can't be found in the database. */ public function test_data_user_can_manage_entry_return_false_no_record(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); // Causes readonly mode to be disabled. $now = time(); $data->timeviewfrom = $now + 100; $data->timeviewto = $now - 100; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); // Pass record id instead of object to force DB lookup. $this->assertFalse(data_user_can_manage_entry(1, $data, $context), 'data_user_can_manage_entry() returns false if the record cannot be found'); } /** * Checks that data_user_can_manage_entry will return false if the record * isn't owned by the user. */ public function test_data_user_can_manage_entry_return_false_not_owned_record(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); // Causes readonly mode to be disabled. $now = time(); $data->timeviewfrom = $now + 100; $data->timeviewto = $now - 100; // Make sure the record isn't owned by this user. $record->userid = $user->id + 1; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); $this->assertFalse(data_user_can_manage_entry($record, $data, $context), 'data_user_can_manage_entry() returns false if the record isnt owned by the user'); } /** * Checks that data_user_can_manage_entry will return true if the data * doesn't require approval. */ public function test_data_user_can_manage_entry_return_true_data_no_approval(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); // Causes readonly mode to be disabled. $now = time(); $data->timeviewfrom = $now + 100; $data->timeviewto = $now - 100; // The record doesn't need approval. $data->approval = false; // Make sure the record is owned by this user. $record->userid = $user->id; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 'data_user_can_manage_entry() returns true if the record doesnt require approval'); } /** * Checks that data_user_can_manage_entry will return true if the record * isn't yet approved. */ public function test_data_user_can_manage_entry_return_true_record_unapproved(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); // Causes readonly mode to be disabled. $now = time(); $data->timeviewfrom = $now + 100; $data->timeviewto = $now - 100; // The record needs approval. $data->approval = true; // Make sure the record is owned by this user. $record->userid = $user->id; // The record hasn't yet been approved. $record->approved = false; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); $this->assertTrue(data_user_can_manage_entry($record, $data, $context), 'data_user_can_manage_entry() returns true if the record is not yet approved'); } /** * Checks that data_user_can_manage_entry will return the 'manageapproved' * value if the record has already been approved. */ public function test_data_user_can_manage_entry_return_manageapproved(): void { $this->resetAfterTest(); $testdata = $this->create_user_test_data(); $user = $testdata['user']; $course = $testdata['course']; $roleid = $testdata['roleid']; $context = $testdata['context']; $record = $testdata['record']; $data = new \stdClass(); // Causes readonly mode to be disabled. $now = time(); $data->timeviewfrom = $now + 100; $data->timeviewto = $now - 100; // The record needs approval. $data->approval = true; // Can the user managed approved records? $data->manageapproved = false; // Make sure the record is owned by this user. $record->userid = $user->id; // The record has been approved. $record->approved = true; $this->setUser($user); // Need to make sure they don't have this capability in order to fall back to // the other checks. assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context); $canmanageentry = data_user_can_manage_entry($record, $data, $context); // Make sure the result of the check is what ever the manageapproved setting // is set to. $this->assertEquals($data->manageapproved, $canmanageentry, 'data_user_can_manage_entry() returns the manageapproved setting on approved records'); } /** * Helper method to create a set of test data for data_user_can_manage tests * * @return array contains user, course, roleid, module, context and record */ private function create_user_test_data() { $user = $this->getDataGenerator()->create_user(); $course = $this->getDataGenerator()->create_course(); $roleid = $this->getDataGenerator()->create_role(); $record = new \stdClass(); $record->name = "test name"; $record->intro = "test intro"; $record->comments = 1; $record->course = $course->id; $record->userid = $user->id; $module = $this->getDataGenerator()->create_module('data', $record); $cm = get_coursemodule_from_instance('data', $module->id, $course->id); $context = \context_module::instance($module->cmid); $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id); return array( 'user' => $user, 'course' => $course, 'roleid' => $roleid, 'module' => $module, 'context' => $context, 'record' => $record ); } /** * Tests for mod_data_rating_can_see_item_ratings(). * * @throws coding_exception * @throws rating_exception */ public function test_mod_data_rating_can_see_item_ratings(): void { global $DB; $this->resetAfterTest(); // Setup test data. $course = new \stdClass(); $course->groupmode = SEPARATEGROUPS; $course->groupmodeforce = true; $course = $this->getDataGenerator()->create_course($course); $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); $cm = get_coursemodule_from_instance('data', $data->id); $context = \context_module::instance($cm->id); // Create users. $user1 = $this->getDataGenerator()->create_user(); $user2 = $this->getDataGenerator()->create_user(); $user3 = $this->getDataGenerator()->create_user(); $user4 = $this->getDataGenerator()->create_user(); // Groups and stuff. $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST); $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id); $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id); $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id); $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id); $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id)); groups_add_member($group1, $user1); groups_add_member($group1, $user2); groups_add_member($group2, $user3); groups_add_member($group2, $user4); // Add data. $field = data_get_field_new('text', $data); $fielddetail = new \stdClass(); $fielddetail->name = 'Name'; $fielddetail->description = 'Some name'; $field->define_field($fielddetail); $field->insert_field(); // Add a record with a group id of zero (all participants). $recordid1 = data_add_record($data, 0); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid1; $datacontent['content'] = 'Obelix'; $DB->insert_record('data_content', $datacontent); $recordid = data_add_record($data, $group1->id); $datacontent = array(); $datacontent['fieldid'] = $field->field->id; $datacontent['recordid'] = $recordid; $datacontent['content'] = 'Asterix'; $DB->insert_record('data_content', $datacontent); // Now try to access it as various users. unassign_capability('moodle/site:accessallgroups', $role->id); // Eveyone should have access to the record with the group id of zero. $params1 = array('contextid' => 2, 'component' => 'mod_data', 'ratingarea' => 'entry', 'itemid' => $recordid1, 'scaleid' => 2); $params = array('contextid' => 2, 'component' => 'mod_data', 'ratingarea' => 'entry', 'itemid' => $recordid, 'scaleid' => 2); $this->setUser($user1); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user2); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user3); $this->assertFalse(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user4); $this->assertFalse(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); // Now try with accessallgroups cap and make sure everything is visible. assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id); $this->setUser($user1); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user2); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user3); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user4); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); // Change group mode and verify visibility. $course->groupmode = VISIBLEGROUPS; $DB->update_record('course', $course); unassign_capability('moodle/site:accessallgroups', $role->id); $this->setUser($user1); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user2); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user3); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); $this->setUser($user4); $this->assertTrue(mod_data_rating_can_see_item_ratings($params)); $this->assertTrue(mod_data_rating_can_see_item_ratings($params1)); } /** * Tests for mod_data_refresh_events. */ public function test_data_refresh_events(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $timeopen = time(); $timeclose = time() + 86400; $course = $this->getDataGenerator()->create_course(); $generator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $params['course'] = $course->id; $params['timeavailablefrom'] = $timeopen; $params['timeavailableto'] = $timeclose; $data = $generator->create_instance($params); // Normal case, with existing course. $this->assertTrue(data_refresh_events($course->id)); $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'open'); $openevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST); $this->assertEquals($openevent->timestart, $timeopen); $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'close'); $closeevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST); $this->assertEquals($closeevent->timestart, $timeclose); // In case the course ID is passed as a numeric string. $this->assertTrue(data_refresh_events('' . $course->id)); // Course ID not provided. $this->assertTrue(data_refresh_events()); $eventparams = array('modulename' => 'data'); $events = $DB->get_records('event', $eventparams); foreach ($events as $event) { if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'open') { $this->assertEquals($event->timestart, $timeopen); } if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'close') { $this->assertEquals($event->timestart, $timeclose); } } } /** * Data provider for tests of data_get_config. * * @return array */ public static function data_get_config_provider(): array { $initialdata = (object) [ 'template_foo' => true, 'template_bar' => false, 'template_baz' => null, ]; $database = (object) [ 'config' => json_encode($initialdata), ]; return [ 'Return full dataset (no key/default)' => [ [$database], $initialdata, ], 'Return full dataset (no default)' => [ [$database, null], $initialdata, ], 'Return full dataset' => [ [$database, null, null], $initialdata, ], 'Return requested key only, value true, no default' => [ [$database, 'template_foo'], true, ], 'Return requested key only, value false, no default' => [ [$database, 'template_bar'], false, ], 'Return requested key only, value null, no default' => [ [$database, 'template_baz'], null, ], 'Return unknown key, value null, no default' => [ [$database, 'template_bum'], null, ], 'Return requested key only, value true, default null' => [ [$database, 'template_foo', null], true, ], 'Return requested key only, value false, default null' => [ [$database, 'template_bar', null], false, ], 'Return requested key only, value null, default null' => [ [$database, 'template_baz', null], null, ], 'Return unknown key, value null, default null' => [ [$database, 'template_bum', null], null, ], 'Return requested key only, value true, default 42' => [ [$database, 'template_foo', 42], true, ], 'Return requested key only, value false, default 42' => [ [$database, 'template_bar', 42], false, ], 'Return requested key only, value null, default 42' => [ [$database, 'template_baz', 42], null, ], 'Return unknown key, value null, default 42' => [ [$database, 'template_bum', 42], 42, ], ]; } /** * Tests for data_get_config. * * @dataProvider data_get_config_provider * @param array $funcargs The args to pass to data_get_config * @param mixed $expectation The expected value */ public function test_data_get_config($funcargs, $expectation): void { $this->assertEquals($expectation, call_user_func_array('data_get_config', $funcargs)); } /** * Data provider for tests of data_set_config. * * @return array */ public static function data_set_config_provider(): array { $basevalue = (object) ['id' => rand(1, 1000)]; $config = [ 'template_foo' => true, 'template_bar' => false, ]; $withvalues = clone $basevalue; $withvalues->config = json_encode((object) $config); return [ 'Empty config, New value' => [ $basevalue, 'etc', 'newvalue', true, json_encode((object) ['etc' => 'newvalue']) ], 'Has config, New value' => [ clone $withvalues, 'etc', 'newvalue', true, json_encode((object) array_merge($config, ['etc' => 'newvalue'])) ], 'Has config, Update value, string' => [ clone $withvalues, 'template_foo', 'newvalue', true, json_encode((object) array_merge($config, ['template_foo' => 'newvalue'])) ], 'Has config, Update value, true' => [ clone $withvalues, 'template_bar', true, true, json_encode((object) array_merge($config, ['template_bar' => true])) ], 'Has config, Update value, false' => [ clone $withvalues, 'template_foo', false, true, json_encode((object) array_merge($config, ['template_foo' => false])) ], 'Has config, Update value, null' => [ clone $withvalues, 'template_foo', null, true, json_encode((object) array_merge($config, ['template_foo' => null])) ], 'Has config, No update, value true' => [ clone $withvalues, 'template_foo', true, false, $withvalues->config, ], ]; } /** * Tests for data_set_config. * * @dataProvider data_set_config_provider * @param object $database The example row for the entry * @param string $key The config key to set * @param mixed $value The value of the key * @param bool $expectupdate Whether we expected an update * @param mixed $newconfigvalue The expected value */ public function test_data_set_config($database, $key, $value, $expectupdate, $newconfigvalue): void { global $DB; // Mock the database. // Note: Use the actual test class here rather than the abstract because are testing concrete methods. $this->DB = $DB; $DB = $this->getMockBuilder(get_class($DB)) ->onlyMethods(['set_field']) ->getMock(); $DB->expects($this->exactly((int) $expectupdate)) ->method('set_field') ->with( 'data', 'config', $newconfigvalue, ['id' => $database->id] ); // Perform the update. data_set_config($database, $key, $value); // Ensure that the value was updated by reference in $database. $config = json_decode($database->config); $this->assertEquals($value, $config->$key); } public function test_mod_data_get_tagged_records(): void { $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $course1 = $this->getDataGenerator()->create_course(); $fieldrecord = new \stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); $field1 = $datagenerator->create_field($fieldrecord, $data1); $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']); $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Cats']); $datagenerator->create_entry($data1, [$field1->field->id => 'value14'], 0); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value12', $res->content); $this->assertStringContainsString('value13', $res->content); $this->assertStringNotContainsString('value14', $res->content); } public function test_mod_data_get_tagged_records_approval(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $course2 = $this->getDataGenerator()->create_course(); $course1 = $this->getDataGenerator()->create_course(); $fieldrecord = new \stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id)); $field1 = $datagenerator->create_field($fieldrecord, $data1); $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 'approval' => true)); $field2 = $datagenerator->create_field($fieldrecord, $data2); $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats'], ['approved' => false]); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertEmpty($res->prevpageurl); $this->assertEmpty($res->nextpageurl); // Create and enrol a user. $student = self::getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); $this->setUser($student); // User can search data records inside a course. \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringNotContainsString('value21', $res->content); $recordtoupdate = new \stdClass(); $recordtoupdate->id = $record21; $recordtoupdate->approved = true; $DB->update_record('data_records', $recordtoupdate); \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); } public function test_mod_data_get_tagged_records_time(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $course2 = $this->getDataGenerator()->create_course(); $course1 = $this->getDataGenerator()->create_course(); $fieldrecord = new \stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $timefrom = time() - YEARSECS; $timeto = time() - WEEKSECS; $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); $field1 = $datagenerator->create_field($fieldrecord, $data1); $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 'timeviewfrom' => $timefrom, 'timeviewto' => $timeto)); $field2 = $datagenerator->create_field($fieldrecord, $data2); $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertEmpty($res->prevpageurl); $this->assertEmpty($res->nextpageurl); // Create and enrol a user. $student = self::getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); $this->setUser($student); // User can search data records inside a course. \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringNotContainsString('value21', $res->content); $data2->timeviewto = time() + YEARSECS; $DB->update_record('data', $data2); \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); } public function test_mod_data_get_tagged_records_course_enrolment(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $course2 = $this->getDataGenerator()->create_course(); $course1 = $this->getDataGenerator()->create_course(); $fieldrecord = new \stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); $field1 = $datagenerator->create_field($fieldrecord, $data1); $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id)); $field2 = $datagenerator->create_field($fieldrecord, $data2); $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertEmpty($res->prevpageurl); $this->assertEmpty($res->nextpageurl); // Create and enrol a user. $student = self::getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); $this->setUser($student); \core_tag_index_builder::reset_caches(); // User can search data records inside a course. $coursecontext = \context_course::instance($course1->id); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringNotContainsString('value21', $res->content); $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); } public function test_mod_data_get_tagged_records_course_groups(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); // Setup test data. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $course2 = $this->getDataGenerator()->create_course(); $course1 = $this->getDataGenerator()->create_course(); $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupA')); $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupB')); $fieldrecord = new \stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true)); $field1 = $datagenerator->create_field($fieldrecord, $data1); $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id)); $field2 = $datagenerator->create_field($fieldrecord, $data2); set_coursemodule_groupmode($data2->cmid, SEPARATEGROUPS); $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']); $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], $groupa->id, ['Cats']); $record22 = $datagenerator->create_entry($data2, [$field2->field->id => 'value22'], $groupb->id, ['Cats']); $tag = \core_tag_tag::get_by_name(0, 'Cats'); // Admin can see everything. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertStringContainsString('value22', $res->content); $this->assertEmpty($res->prevpageurl); $this->assertEmpty($res->nextpageurl); // Create and enrol a user. $student = self::getDataGenerator()->create_user(); $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual'); $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual'); groups_add_member($groupa, $student); $this->setUser($student); \core_tag_index_builder::reset_caches(); // User can search data records inside a course. $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertStringNotContainsString('value22', $res->content); groups_add_member($groupb, $student); \core_tag_index_builder::reset_caches(); $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0); $this->assertStringContainsString('value11', $res->content); $this->assertStringContainsString('value21', $res->content); $this->assertStringContainsString('value22', $res->content); } /** * Test check_updates_since callback. */ public function test_check_updates_since(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); // Create user. $student = self::getDataGenerator()->create_user(); // User enrolment. $studentrole = $DB->get_record('role', array('shortname' => 'student')); $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual'); $this->setCurrentTimeStart(); $record = array( 'course' => $course->id, ); $data = $this->getDataGenerator()->create_module('data', $record); $cm = get_coursemodule_from_instance('data', $data->id, $course->id); $cm = \cm_info::create($cm); $this->setUser($student); // Check that upon creation, the updates are only about the new configuration created. $onehourago = time() - HOURSECS; $updates = data_check_updates_since($cm, $onehourago); foreach ($updates as $el => $val) { if ($el == 'configuration') { $this->assertTrue($val->updated); $this->assertTimeCurrent($val->timeupdated); } else { $this->assertFalse($val->updated); } } // Add a couple of entries. $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $fieldtypes = array('checkbox', 'date'); $count = 1; // Creating test Fields with default parameter values. foreach ($fieldtypes as $fieldtype) { // Creating variables dynamically. $fieldname = 'field-' . $count; $record = new \stdClass(); $record->name = $fieldname; $record->type = $fieldtype; $record->required = 1; ${$fieldname} = $datagenerator->create_field($record, $data); $count++; } $fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id'); $contents = array(); $contents[] = array('opt1', 'opt2', 'opt3', 'opt4'); $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows. $count = 0; $fieldcontents = array(); foreach ($fields as $fieldrecord) { $fieldcontents[$fieldrecord->id] = $contents[$count++]; } $datarecor1did = $datagenerator->create_entry($data, $fieldcontents); $datarecor2did = $datagenerator->create_entry($data, $fieldcontents); $records = $DB->get_records('data_records', array('dataid' => $data->id)); $this->assertCount(2, $records); // Check we received the entries updated. $updates = data_check_updates_since($cm, $onehourago); $this->assertTrue($updates->entries->updated); $this->assertEqualsCanonicalizing([$datarecor1did, $datarecor2did], $updates->entries->itemids); } public function test_data_core_calendar_provide_event_action_in_hidden_section(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Set sections 0 as hidden. set_section_visible($course->id, 0, 0); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event is not shown at all. $this->assertNull($actionevent); } public function test_data_core_calendar_provide_event_action_for_non_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Now, log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); // Confirm the event is not shown at all. $this->assertNull($actionevent); } public function test_data_core_calendar_provide_event_action_open(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_data_core_calendar_provide_event_action_open_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Now log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_data_core_calendar_provide_event_action_closed(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailableto' => time() - DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); // No event on the dashboard if module is closed. $this->assertNull($actionevent); } public function test_data_core_calendar_provide_event_action_closed_for_user(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailableto' => time() - DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Now log out. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); // No event on the dashboard if module is closed. $this->assertNull($actionevent); } public function test_data_core_calendar_provide_event_action_open_in_future(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertFalse($actionevent->is_actionable()); } public function test_data_core_calendar_provide_event_action_open_in_future_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id, 'timeavailablefrom' => time() + DAYSECS)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Now log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertFalse($actionevent->is_actionable()); } public function test_data_core_calendar_provide_event_action_no_time_specified(): void { $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } public function test_data_core_calendar_provide_event_action_no_time_specified_for_user(): void { global $CFG; $this->resetAfterTest(); $this->setAdminUser(); // Create a course. $course = $this->getDataGenerator()->create_course(); // Create a student. $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); // Create a database activity. $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id)); // Create a calendar event. $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN); // Now log out. $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities. $this->setUser(); // Create an action factory. $factory = new \core_calendar\action_factory(); // Decorate action event for the student. $actionevent = mod_data_core_calendar_provide_event_action($event, $factory, $student->id); // Confirm the event was decorated. $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent); $this->assertEquals(get_string('add', 'data'), $actionevent->get_name()); $this->assertInstanceOf('moodle_url', $actionevent->get_url()); $this->assertEquals(1, $actionevent->get_item_count()); $this->assertTrue($actionevent->is_actionable()); } /** * Creates an action event. * * @param int $courseid * @param int $instanceid The data id. * @param string $eventtype The event type. eg. DATA_EVENT_TYPE_OPEN. * @param int|null $timestart The start timestamp for the event * @return bool|calendar_event */ private function create_action_event($courseid, $instanceid, $eventtype, $timestart = null) { $event = new \stdClass(); $event->name = 'Calendar event'; $event->modulename = 'data'; $event->courseid = $courseid; $event->instance = $instanceid; $event->type = CALENDAR_EVENT_TYPE_ACTION; $event->eventtype = $eventtype; if ($timestart) { $event->timestart = $timestart; } else { $event->timestart = time(); } return \calendar_event::create($event); } /** * Test the callback responsible for returning the completion rule descriptions. * This function should work given either an instance of the module (cm_info), such as when checking the active rules, * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type. */ public function test_mod_data_completion_get_active_rule_descriptions(): void { $this->resetAfterTest(); $this->setAdminUser(); // Two activities, both with automatic completion. One has the 'completionentries' rule, one doesn't. $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]); $data1 = $this->getDataGenerator()->create_module('data', [ 'course' => $course->id, 'completion' => 2, 'completionentries' => 3 ]); $data2 = $this->getDataGenerator()->create_module('data', [ 'course' => $course->id, 'completion' => 2, 'completionentries' => 0 ]); $cm1 = \cm_info::create(get_coursemodule_from_instance('data', $data1->id)); $cm2 = \cm_info::create(get_coursemodule_from_instance('data', $data2->id)); // Data for the stdClass input type. // This type of input would occur when checking the default completion rules for an activity type, where we don't have // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info. $moddefaults = new \stdClass(); $moddefaults->customdata = ['customcompletionrules' => ['completionentries' => 3]]; $moddefaults->completion = 2; $activeruledescriptions = [get_string('completionentriesdesc', 'data', 3)]; $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm1), $activeruledescriptions); $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm2), []); $this->assertEquals(mod_data_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions); $this->assertEquals(mod_data_get_completion_active_rule_descriptions(new \stdClass()), []); } /** * An unknown event type should not change the data instance. */ public function test_mod_data_core_calendar_event_timestart_updated_unknown_event(): void { global $CFG, $DB; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $datagenerator = $generator->get_plugin_generator('mod_data'); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $data = $datagenerator->create_instance(['course' => $course->id]); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; $DB->update_record('data', $data); // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => $data->id, 'eventtype' => DATA_EVENT_TYPE_OPEN . "SOMETHING ELSE", 'timestart' => 1, 'timeduration' => 86400, 'visible' => 1 ]); mod_data_core_calendar_event_timestart_updated($event, $data); $data = $DB->get_record('data', ['id' => $data->id]); $this->assertEquals($timeopen, $data->timeavailablefrom); $this->assertEquals($timeclose, $data->timeavailableto); } /** * A DATA_EVENT_TYPE_OPEN event should update the timeavailablefrom property of the data activity. */ public function test_mod_data_core_calendar_event_timestart_updated_open_event(): void { global $CFG, $DB; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $datagenerator = $generator->get_plugin_generator('mod_data'); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $timemodified = 1; $newtimeopen = $timeopen - DAYSECS; $data = $datagenerator->create_instance(['course' => $course->id]); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; $data->timemodified = $timemodified; $DB->update_record('data', $data); // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => $data->id, 'eventtype' => DATA_EVENT_TYPE_OPEN, 'timestart' => $newtimeopen, 'timeduration' => 86400, 'visible' => 1 ]); // Trigger and capture the event when adding a contact. $sink = $this->redirectEvents(); mod_data_core_calendar_event_timestart_updated($event, $data); $triggeredevents = $sink->get_events(); $moduleupdatedevents = array_filter($triggeredevents, function($e) { return is_a($e, 'core\event\course_module_updated'); }); $data = $DB->get_record('data', ['id' => $data->id]); // Ensure the timeavailablefrom property matches the event timestart. $this->assertEquals($newtimeopen, $data->timeavailablefrom); // Ensure the timeavailableto isn't changed. $this->assertEquals($timeclose, $data->timeavailableto); // Ensure the timemodified property has been changed. $this->assertNotEquals($timemodified, $data->timemodified); // Confirm that a module updated event is fired when the module is changed. $this->assertNotEmpty($moduleupdatedevents); } /** * A DATA_EVENT_TYPE_CLOSE event should update the timeavailableto property of the data activity. */ public function test_mod_data_core_calendar_event_timestart_updated_close_event(): void { global $CFG, $DB; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $datagenerator = $generator->get_plugin_generator('mod_data'); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $timemodified = 1; $newtimeclose = $timeclose + DAYSECS; $data = $datagenerator->create_instance(['course' => $course->id]); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; $data->timemodified = $timemodified; $DB->update_record('data', $data); // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => $data->id, 'eventtype' => DATA_EVENT_TYPE_CLOSE, 'timestart' => $newtimeclose, 'timeduration' => 86400, 'visible' => 1 ]); // Trigger and capture the event when adding a contact. $sink = $this->redirectEvents(); mod_data_core_calendar_event_timestart_updated($event, $data); $triggeredevents = $sink->get_events(); $moduleupdatedevents = array_filter($triggeredevents, function($e) { return is_a($e, 'core\event\course_module_updated'); }); $data = $DB->get_record('data', ['id' => $data->id]); // Ensure the timeavailableto property matches the event timestart. $this->assertEquals($newtimeclose, $data->timeavailableto); // Ensure the timeavailablefrom isn't changed. $this->assertEquals($timeopen, $data->timeavailablefrom); // Ensure the timemodified property has been changed. $this->assertNotEquals($timemodified, $data->timemodified); // Confirm that a module updated event is fired when the module is changed. $this->assertNotEmpty($moduleupdatedevents); } /** * An unknown event type should not have any limits. */ public function test_mod_data_core_calendar_get_valid_event_timestart_range_unknown_event(): void { global $CFG; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $data = new \stdClass(); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => 1, 'eventtype' => DATA_EVENT_TYPE_OPEN . "SOMETHING ELSE", 'timestart' => 1, 'timeduration' => 86400, 'visible' => 1 ]); list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); $this->assertNull($min); $this->assertNull($max); } /** * The open event should be limited by the data's timeclose property, if it's set. */ public function test_mod_data_core_calendar_get_valid_event_timestart_range_open_event(): void { global $CFG; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $data = new \stdClass(); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => 1, 'eventtype' => DATA_EVENT_TYPE_OPEN, 'timestart' => 1, 'timeduration' => 86400, 'visible' => 1 ]); // The max limit should be bounded by the timeclose value. list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); $this->assertNull($min); $this->assertEquals($timeclose, $max[0]); // No timeclose value should result in no upper limit. $data->timeavailableto = 0; list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); $this->assertNull($min); $this->assertNull($max); } /** * The close event should be limited by the data's timeavailablefrom property, if it's set. */ public function test_mod_data_core_calendar_get_valid_event_timestart_range_close_event(): void { global $CFG; require_once($CFG->dirroot . "/calendar/lib.php"); $this->resetAfterTest(true); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $timeopen = time(); $timeclose = $timeopen + DAYSECS; $data = new \stdClass(); $data->timeavailablefrom = $timeopen; $data->timeavailableto = $timeclose; // Create a valid event. $event = new \calendar_event([ 'name' => 'Test event', 'description' => '', 'format' => 1, 'courseid' => $course->id, 'groupid' => 0, 'userid' => 2, 'modulename' => 'data', 'instance' => 1, 'eventtype' => DATA_EVENT_TYPE_CLOSE, 'timestart' => 1, 'timeduration' => 86400, 'visible' => 1 ]); // The max limit should be bounded by the timeclose value. list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); $this->assertEquals($timeopen, $min[0]); $this->assertNull($max); // No timeavailableto value should result in no upper limit. $data->timeavailablefrom = 0; list ($min, $max) = mod_data_core_calendar_get_valid_event_timestart_range($event, $data); $this->assertNull($min); $this->assertNull($max); } /** * A user who does not have capabilities to add events to the calendar should be able to create an database. */ public function test_creation_with_no_calendar_capabilities(): void { $this->resetAfterTest(); $course = self::getDataGenerator()->create_course(); $context = \context_course::instance($course->id); $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher'); $roleid = self::getDataGenerator()->create_role(); self::getDataGenerator()->role_assign($roleid, $user->id, $context->id); assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true); $generator = self::getDataGenerator()->get_plugin_generator('mod_data'); // Create an instance as a user without the calendar capabilities. $this->setUser($user); $time = time(); $params = array( 'course' => $course->id, 'timeavailablefrom' => $time + 200, 'timeavailableto' => $time + 2000, 'timeviewfrom' => $time + 400, 'timeviewto' => $time + 2000, ); $generator->create_instance($params); } /** * Test for data_generate_default_template(). This method covers different scenarios for checking when the returned value * is empty or not, but doesn't check if the content has the expected value when it's not empty. * * @covers ::data_generate_default_template */ public function test_data_generate_default_template(): void { $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]); // Check the result is empty when $data and/or $template are null. $nullactivity = null; $result = data_generate_default_template($nullactivity, 'listtemplate', 0, false, false); $this->assertEmpty($result); $result = data_generate_default_template($activity, null, 0, false, false); $this->assertEmpty($result); $result = data_generate_default_template($nullactivity, null, 0, false, false); $this->assertEmpty($result); // Check the result is empty when any of the templates that are empty are given. $emptytemplates = [ 'csstemplate', 'jstemplate', 'listtemplateheader', 'listtemplatefooter', 'rsstitletemplate', ]; foreach ($emptytemplates as $emptytemplate) { $result = data_generate_default_template($activity, $emptytemplate, 0, false, false); $this->assertEmpty($result); } $templates = [ 'listtemplate', 'singletemplate', 'asearchtemplate', ]; // Check the result is empty when the database has no fields. foreach ($templates as $template) { $result = data_generate_default_template($activity, $template, 0, false, false); $this->assertEmpty($result); $this->assertEmpty($activity->{$template}); } // Add a field to the activity. $fieldrecord = new stdClass(); $fieldrecord->name = 'field-1'; $fieldrecord->type = 'text'; $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data'); $datagenerator->create_field($fieldrecord, $activity); // Check the result is not empty when the database has no entries. foreach ($templates as $template) { $result = data_generate_default_template($activity, $template, 0, false, false); $this->assertNotEmpty($result); $this->assertEmpty($activity->{$template}); } // Check the result is not empty when the database has no entries and the result is saved when $update = true. foreach ($templates as $template) { $result = data_generate_default_template($activity, $template, 0, false, true); $this->assertNotEmpty($result); $this->assertNotEmpty($activity->{$template}); } } /** * Test for data_replace_field_in_templates(). * * @covers ::data_replace_field_in_templates */ public function test_data_replace_field_in_templates(): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $course = $this->getDataGenerator()->create_course(); $templatecontent = "Field [[myfield]], [[myfield#id]], [[myfield#name]], [[myfield#description]], "; $params = ['course' => $course]; foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) { $params[$templatename] = $templatecontent; } $activity = $this->getDataGenerator()->create_module(manager::MODULE, $params); $generator = $this->getDataGenerator()->get_plugin_generator(manager::PLUGINNAME); $fieldrecord = (object)['name' => 'myfield', 'type' => 'text', 'description' => 'This is a field']; $generator->create_field($fieldrecord, $activity); data_replace_field_in_templates($activity, 'myfield', 'newfieldname'); $dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]); $newcontent = "Field [[newfieldname]], [[newfieldname#id]], [[newfieldname#name]], [[newfieldname#description]], "; // Field compatible templates. $this->assertEquals($newcontent, $dbactivity->listtemplate); $this->assertEquals($newcontent, $dbactivity->singletemplate); $this->assertEquals($newcontent, $dbactivity->asearchtemplate); $this->assertEquals($newcontent, $dbactivity->addtemplate); $this->assertEquals($newcontent, $dbactivity->rsstemplate); // Other templates. $this->assertEquals($templatecontent, $dbactivity->listtemplateheader); $this->assertEquals($templatecontent, $dbactivity->listtemplatefooter); $this->assertEquals($templatecontent, $dbactivity->csstemplate); $this->assertEquals($templatecontent, $dbactivity->jstemplate); $this->assertEquals($templatecontent, $dbactivity->rsstitletemplate); } /** * Test for data_append_new_field_to_templates(). * * @covers ::data_append_new_field_to_templates * @dataProvider data_append_new_field_to_templates_provider * @param bool $hasfield if the field is present in the templates * @param bool $hasotherfields if the field is not present in the templates * @param bool $expected the expected return */ public function test_data_append_new_field_to_templates(bool $hasfield, bool $hasotherfields, bool $expected): void { global $DB; $this->resetAfterTest(); $this->setAdminUser(); $templatecontent = "Template content"; if ($hasfield) { $templatecontent .= "Has [[myfield]]."; } if ($hasotherfields) { $templatecontent .= "And also ##otherfields##."; } $course = $this->getDataGenerator()->create_course(); $params = ['course' => $course]; foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) { $params[$templatename] = $templatecontent; } $activity = $this->getDataGenerator()->create_module(manager::MODULE, $params); $result = data_append_new_field_to_templates($activity, 'myfield'); $this->assertEquals($expected, $result); // Check fields with auto add fields. $dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]); if ($hasfield || $hasotherfields) { $this->assertEquals($dbactivity->singletemplate, $templatecontent); $this->assertEquals($dbactivity->addtemplate, $templatecontent); $this->assertEquals($dbactivity->rsstemplate, $templatecontent); } else { $regexp = '|Template content.*\[\[myfield\]\]|'; // We don't want line breaks for the validations. $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->singletemplate)); $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->addtemplate)); $this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->rsstemplate)); } // No auto add field templates. $this->assertEquals($dbactivity->asearchtemplate, $templatecontent); $this->assertEquals($dbactivity->listtemplate, $templatecontent); $this->assertEquals($dbactivity->listtemplateheader, $templatecontent); $this->assertEquals($dbactivity->listtemplatefooter, $templatecontent); $this->assertEquals($dbactivity->csstemplate, $templatecontent); $this->assertEquals($dbactivity->jstemplate, $templatecontent); $this->assertEquals($dbactivity->rsstitletemplate, $templatecontent); } /** * Data provider for test_data_append_new_field_to_templates(). * * @return array of scenarios */ public static function data_append_new_field_to_templates_provider(): array { return [ 'Plain template' => [ 'hasfield' => false, 'hasotherfields' => false, 'expected' => true, ], 'Field already present' => [ 'hasfield' => true, 'hasotherfields' => false, 'expected' => false, ], '##otherfields## tag present' => [ 'hasfield' => false, 'hasotherfields' => true, 'expected' => false, ], 'Field already present and ##otherfields## tag present' => [ 'hasfield' => true, 'hasotherfields' => true, 'expected' => false, ], ]; } /** * Test that format that are not supported are raising an exception * * @param string $type * @param string $expected * @covers \data_get_field_new * @dataProvider format_parser_provider */ public function test_create_field(string $type, string $expected): void { $this->resetAfterTest(); $this->setAdminUser(); $generator = $this->getDataGenerator(); $course = $generator->create_course(); $data = $this->getDataGenerator()->create_module('data', ['course' => $course->id] ); if ($expected === 'exception') { $this->expectException(\moodle_exception::class); } $field = data_get_field_new($type, $data); $this->assertStringContainsString($expected, get_class($field)); } /** * Data provider for test_format_parser * * @return array[] */ public static function format_parser_provider(): array { return [ 'text' => [ 'type' => 'text', 'expected' => 'data_field_text', ], 'picture' => [ 'type' => 'picture', 'expected' => 'data_field_picture', ], 'wrong type' => [ 'type' => '../wrongformat123', 'expected' => 'exception', ], ]; } }