Rev 1 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>.namespace core_competency;/*** API 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*/class api_test extends \advanced_testcase {public function test_get_framework_related_contexts(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$cat1 = $dg->create_category();$cat2 = $dg->create_category(array('parent' => $cat1->id));$cat3 = $dg->create_category(array('parent' => $cat2->id));$c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned.$cat1ctx = \context_coursecat::instance($cat1->id);$cat2ctx = \context_coursecat::instance($cat2->id);$cat3ctx = \context_coursecat::instance($cat3->id);$sysctx = \context_system::instance();$expected = array($cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));$expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));$expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));}public function test_get_framework_related_contexts_with_capabilities(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$user = $dg->create_user();$cat1 = $dg->create_category();$cat2 = $dg->create_category(array('parent' => $cat1->id));$cat3 = $dg->create_category(array('parent' => $cat2->id));$c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned.$cat1ctx = \context_coursecat::instance($cat1->id);$cat2ctx = \context_coursecat::instance($cat2->id);$cat3ctx = \context_coursecat::instance($cat3->id);$sysctx = \context_system::instance();$roleallow = create_role('Allow', 'allow', 'Allow read');assign_capability('moodle/competency:competencyview', CAP_ALLOW, $roleallow, $sysctx->id);role_assign($roleallow, $user->id, $sysctx->id);$roleprevent = create_role('Prevent', 'prevent', 'Prevent read');assign_capability('moodle/competency:competencyview', CAP_PROHIBIT, $roleprevent, $sysctx->id);role_assign($roleprevent, $user->id, $cat2ctx->id);accesslib_clear_all_caches_for_unit_testing();$this->setUser($user);$this->assertFalse(has_capability('moodle/competency:competencyview', $cat2ctx));$requiredcap = array('moodle/competency:competencyview');$expected = array();$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));$expected = array($cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));$expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));}public function test_get_template_related_contexts(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$cat1 = $dg->create_category();$cat2 = $dg->create_category(array('parent' => $cat1->id));$cat3 = $dg->create_category(array('parent' => $cat2->id));$c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned.$cat1ctx = \context_coursecat::instance($cat1->id);$cat2ctx = \context_coursecat::instance($cat2->id);$cat3ctx = \context_coursecat::instance($cat3->id);$sysctx = \context_system::instance();$expected = array($cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));$expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));$expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));}public function test_get_template_related_contexts_with_capabilities(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$user = $dg->create_user();$cat1 = $dg->create_category();$cat2 = $dg->create_category(array('parent' => $cat1->id));$cat3 = $dg->create_category(array('parent' => $cat2->id));$c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned.$cat1ctx = \context_coursecat::instance($cat1->id);$cat2ctx = \context_coursecat::instance($cat2->id);$cat3ctx = \context_coursecat::instance($cat3->id);$sysctx = \context_system::instance();$roleallow = create_role('Allow', 'allow', 'Allow read');assign_capability('moodle/competency:templateview', CAP_ALLOW, $roleallow, $sysctx->id);role_assign($roleallow, $user->id, $sysctx->id);$roleprevent = create_role('Prevent', 'prevent', 'Prevent read');assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $roleprevent, $sysctx->id);role_assign($roleprevent, $user->id, $cat2ctx->id);accesslib_clear_all_caches_for_unit_testing();$this->setUser($user);$this->assertFalse(has_capability('moodle/competency:templateview', $cat2ctx));$requiredcap = array('moodle/competency:templateview');$expected = array();$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));$expected = array($cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));$expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);$this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));}/*** Test updating a template.*/public function test_update_template(): void {$cat = $this->getDataGenerator()->create_category();$this->resetAfterTest(true);$this->setAdminUser();$syscontext = \context_system::instance();$template = api::create_template((object) array('shortname' => 'testing', 'contextid' => $syscontext->id));$this->assertEquals('testing', $template->get('shortname'));$this->assertEquals($syscontext->id, $template->get('contextid'));// Simple update.api::update_template((object) array('id' => $template->get('id'), 'shortname' => 'success'));$template = api::read_template($template->get('id'));$this->assertEquals('success', $template->get('shortname'));// Trying to change the context.$this->expectException(\coding_exception::class);api::update_template((object) ['id' => $template->get('id'), 'contextid' => \context_coursecat::instance($cat->id)->id]);}/*** Test listing framework with order param.*/public function test_list_frameworks(): void {$this->resetAfterTest(true);$this->setAdminUser();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');// Create a list of frameworks.$framework1 = $lpg->create_framework(array('shortname' => 'shortname_alpha','idnumber' => 'idnumber_cinnamon','description' => 'description','descriptionformat' => FORMAT_HTML,'visible' => true,'contextid' => \context_system::instance()->id));$framework2 = $lpg->create_framework(array('shortname' => 'shortname_beetroot','idnumber' => 'idnumber_apple','description' => 'description','descriptionformat' => FORMAT_HTML,'visible' => true,'contextid' => \context_system::instance()->id));$framework3 = $lpg->create_framework(array('shortname' => 'shortname_crisps','idnumber' => 'idnumber_beer','description' => 'description','descriptionformat' => FORMAT_HTML,'visible' => false,'contextid' => \context_system::instance()->id));// Get frameworks list order by shortname desc.$result = api::list_frameworks('shortname', 'DESC', null, 3, \context_system::instance());$f = (object) array_shift($result);$this->assertEquals($framework3->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework2->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework1->get('id'), $f->get('id'));// Get frameworks list order by idnumber asc.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance());$f = (object) array_shift($result);$this->assertEquals($framework2->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework3->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework1->get('id'), $f->get('id'));// Repeat excluding the non-visible ones.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance(), 'self', true);$this->assertCount(2, $result);$f = (object) array_shift($result);$this->assertEquals($framework2->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework1->get('id'), $f->get('id'));// Search by query string, trying match on shortname.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance(), 'self', false, 'crisp');$this->assertCount(1, $result);$f = (object) array_shift($result);$this->assertEquals($framework3->get('id'), $f->get('id'));// Search by query string, trying match on shortname, but hidden.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance(), 'self', true, 'crisp');$this->assertCount(0, $result);// Search by query string, trying match on ID number.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance(), 'self', false, 'apple');$this->assertCount(1, $result);$f = (object) array_shift($result);$this->assertEquals($framework2->get('id'), $f->get('id'));// Search by query string, trying match on both.$result = api::list_frameworks('idnumber', 'ASC', null, 3, \context_system::instance(), 'self', false, 'bee');$this->assertCount(2, $result);$f = (object) array_shift($result);$this->assertEquals($framework2->get('id'), $f->get('id'));$f = (object) array_shift($result);$this->assertEquals($framework3->get('id'), $f->get('id'));}/*** Test duplicate a framework.*/public function test_duplicate_framework(): void {$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$this->resetAfterTest(true);$this->setAdminUser();$syscontext = \context_system::instance();$params = array('shortname' => 'shortname_a','idnumber' => 'idnumber_c','description' => 'description','descriptionformat' => FORMAT_HTML,'visible' => true,'contextid' => $syscontext->id);$framework = $lpg->create_framework($params);$competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$competency3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$competency4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$competency41 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),'parentid' => $competency4->get('id')));$competency42 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),'parentid' => $competency4->get('id')));$competencyidnumbers = array($competency1->get('idnumber'),$competency2->get('idnumber'),$competency3->get('idnumber'),$competency4->get('idnumber'),$competency41->get('idnumber'),$competency42->get('idnumber'));$config = json_encode(array('base' => array('points' => 4),'competencies' => array(array('id' => $competency41->get('id'), 'points' => 3, 'required' => 0),array('id' => $competency42->get('id'), 'points' => 2, 'required' => 1),)));$competency4->set('ruletype', 'core_competency\competency_rule_points');$competency4->set('ruleoutcome', \core_competency\competency::OUTCOME_EVIDENCE);$competency4->set('ruleconfig', $config);$competency4->update();api::add_related_competency($competency1->get('id'), $competency2->get('id'));api::add_related_competency($competency3->get('id'), $competency4->get('id'));$frameworkduplicated1 = api::duplicate_framework($framework->get('id'));$frameworkduplicated2 = api::duplicate_framework($framework->get('id'));$this->assertEquals($framework->get('idnumber').'_1', $frameworkduplicated1->get('idnumber'));$this->assertEquals($framework->get('idnumber').'_2', $frameworkduplicated2->get('idnumber'));$competenciesfr1 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated1->get('id')));$competenciesfr2 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated2->get('id')));$competencyidsfr1 = array();$competencyidsfr2 = array();foreach ($competenciesfr1 as $cmp) {$competencyidsfr1[] = $cmp->get('idnumber');}foreach ($competenciesfr2 as $cmp) {$competencyidsfr2[] = $cmp->get('idnumber');}$this->assertEmpty(array_diff($competencyidsfr1, $competencyidnumbers));$this->assertEmpty(array_diff($competencyidsfr2, $competencyidnumbers));$this->assertCount(6, $competenciesfr1);$this->assertCount(6, $competenciesfr2);// Test the related competencies.reset($competenciesfr1);$compduplicated1 = current($competenciesfr1);$relatedcompetencies = $compduplicated1->get_related_competencies();$comprelated = current($relatedcompetencies);$this->assertEquals($comprelated->get('idnumber'), $competency2->get('idnumber'));// Check if config rule have been ported correctly.$competency4duplicated = competency::get_record(array('idnumber' => $competency4->get('idnumber'),'competencyframeworkid' => $frameworkduplicated2->get('id')));$configduplicated = json_decode($competency4duplicated->get('ruleconfig'), true);$configorigin = json_decode($config, true);// Check that the 2 config have the same base.$this->assertEquals($configorigin['base'], $configduplicated['base']);$this->assertEquals(count($configorigin['competencies']), count($configduplicated['competencies']));$competencyidsrules = array();foreach ($configduplicated['competencies'] as $key => $value) {// Check that the only difference between the 2 config is id competency.$this->assertEquals(1, count(array_diff($value, $configorigin['competencies'][$key])));$competencyidsrules[] = $value['id'];}$this->assertTrue($competency4duplicated->is_parent_of($competencyidsrules));// Test duplicate an empty framework.$emptyfrm = $lpg->create_framework();$emptyfrmduplicated = api::duplicate_framework($emptyfrm->get('id'));$this->assertEquals($emptyfrm->get('idnumber').'_1', $emptyfrmduplicated->get('idnumber'));$nbcomp = api::count_competencies(array('competencyframeworkid' => $emptyfrmduplicated->get('id')));$this->assertEquals(0, $nbcomp);}/*** Test update plan.*/public function test_update_plan(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$usermanageowndraft = $dg->create_user();$usermanageown = $dg->create_user();$usermanagedraft = $dg->create_user();$usermanage = $dg->create_user();$syscontext = \context_system::instance();// Creating specific roles.$manageowndraftrole = $dg->create_role(array('name' => 'User manage own draft','shortname' => 'manage-own-draft'));$manageownrole = $dg->create_role(array('name' => 'User manage own','shortname' => 'manage-own'));$managedraftrole = $dg->create_role(array('name' => 'User manage draft','shortname' => 'manage-draft'));$managerole = $dg->create_role(array('name' => 'User manage','shortname' => 'manage'));assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);assign_capability('moodle/competency:planmanagedraft', CAP_ALLOW, $managedraftrole, $syscontext->id);assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $managedraftrole, $syscontext->id);assign_capability('moodle/competency:planmanage', CAP_ALLOW, $managerole, $syscontext->id);assign_capability('moodle/competency:planview', CAP_ALLOW, $managerole, $syscontext->id);$dg->role_assign($manageowndraftrole, $usermanageowndraft->id, $syscontext->id);$dg->role_assign($manageownrole, $usermanageown->id, $syscontext->id);$dg->role_assign($managedraftrole, $usermanagedraft->id, $syscontext->id);$dg->role_assign($managerole, $usermanage->id, $syscontext->id);// Create first learning plan with user create draft.$this->setUser($usermanageowndraft);$plan = array ('name' => 'plan own draft','description' => 'plan own draft','userid' => $usermanageowndraft->id);$plan = api::create_plan((object)$plan);$record = $plan->to_record();$record->name = 'plan own draft modified';// Check if user create draft can edit the plan name.$plan = api::update_plan($record);$this->assertInstanceOf('\core_competency\plan', $plan);// The status cannot be changed in this method.$record->status = \core_competency\plan::STATUS_ACTIVE;try {$plan = api::update_plan($record);$this->fail('Updating the status is not allowed.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/To change the status of a plan use the appropriate methods./',$e->getMessage());}// Test when user with manage own plan capability try to edit other user plan.$record->status = \core_competency\plan::STATUS_DRAFT;$record->name = 'plan create draft modified 2';$this->setUser($usermanageown);try {$plan = api::update_plan($record);$this->fail('User with manage own plan capability can only edit his own plan.');} catch (\required_capability_exception $e) {$this->assertTrue(true);}// User with manage plan capability cannot edit the other user plans with status draft.$this->setUser($usermanage);$record->name = 'plan create draft modified 3';try {$plan = api::update_plan($record);$this->fail('User with manage plan capability cannot edit the other user plans with status draft');} catch (\required_capability_exception $e) {$this->assertTrue(true);}// User with manage draft capability can edit other user's learning plan if the status is draft.$this->setUser($usermanagedraft);$record->status = \core_competency\plan::STATUS_DRAFT;$record->name = 'plan manage draft modified 3';$plan = api::update_plan($record);$this->assertInstanceOf('\core_competency\plan', $plan);// User with manage plan capability can create/edit learning plan if status is active/complete.$this->setUser($usermanage);$plan = array ('name' => 'plan create','description' => 'plan create','userid' => $usermanage->id,'status' => \core_competency\plan::STATUS_ACTIVE);$plan = api::create_plan((object)$plan);// Silently transition to complete status to avoid errors about transitioning to complete.$plan->set('status', \core_competency\plan::STATUS_COMPLETE);$plan->update();$record = $plan->to_record();$record->name = 'plan create own modified';try {api::update_plan($record);$this->fail('Completed plan can not be edited');} catch (\coding_exception $e) {$this->assertTrue(true);}}public function test_create_plan_from_template(): void {$this->resetAfterTest(true);$this->setAdminUser();$u1 = $this->getDataGenerator()->create_user();$tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();// Creating a new plan.$plan = api::create_plan_from_template($tpl, $u1->id);$record = $plan->to_record();$this->assertInstanceOf('\core_competency\plan', $plan);$this->assertTrue(\core_competency\plan::record_exists($plan->get('id')));$this->assertEquals($tpl->get('id'), $plan->get('templateid'));$this->assertEquals($u1->id, $plan->get('userid'));$this->assertTrue($plan->is_based_on_template());// Creating a plan that already exists.$plan = api::create_plan_from_template($tpl, $u1->id);$this->assertFalse($plan);// Check that api::create_plan cannot be used.unset($record->id);$this->expectException(\coding_exception::class);$plan = api::create_plan($record);}public function test_update_plan_based_on_template(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u2 = $dg->create_user();$this->setAdminUser();$tpl1 = $lpg->create_template();$tpl2 = $lpg->create_template();$up1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id')));$up2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => null));try {// Trying to remove the template dependency.$record = $up1->to_record();$record->templateid = null;api::update_plan($record);$this->fail('A plan cannot be unlinked using api::update_plan()');} catch (\coding_exception $e) {// All good.}try {// Trying to switch to another template.$record = $up1->to_record();$record->templateid = $tpl2->get('id');api::update_plan($record);$this->fail('A plan cannot be moved to another template.');} catch (\coding_exception $e) {// All good.}try {// Trying to switch to using a template.$record = $up2->to_record();$record->templateid = $tpl1->get('id');api::update_plan($record);$this->fail('A plan cannot be update to use a template.');} catch (\coding_exception $e) {// All good.}}public function test_unlink_plan_from_template(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u2 = $dg->create_user();$this->setAdminUser();$f1 = $lpg->create_framework();$f2 = $lpg->create_framework();$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2a = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$tpl1 = $lpg->create_template();$tpl2 = $lpg->create_template();$tplc1a = $lpg->create_template_competency(array('templateid' => $tpl1->get('id'), 'competencyid' => $c1a->get('id'),'sortorder' => 9));$tplc1b = $lpg->create_template_competency(array('templateid' => $tpl1->get('id'), 'competencyid' => $c1b->get('id'),'sortorder' => 8));$tplc2a = $lpg->create_template_competency(array('templateid' => $tpl2->get('id'), 'competencyid' => $c2a->get('id')));$plan1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id'), 'status' => plan::STATUS_ACTIVE));$plan2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => $tpl2->get('id')));$plan3 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id'), 'status' => plan::STATUS_COMPLETE));// Check that we have what we expect at this stage.$this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get('id'))));$this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get('id'))));$this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan1->get('id'))));$this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get('id'))));$this->assertTrue($plan1->is_based_on_template());$this->assertTrue($plan2->is_based_on_template());// Let's do this!$tpl1comps = \core_competency\template_competency::list_competencies($tpl1->get('id'), true);$tpl2comps = \core_competency\template_competency::list_competencies($tpl2->get('id'), true);api::unlink_plan_from_template($plan1);$plan1->read();$plan2->read();$this->assertCount(2, $tpl1comps);$this->assertCount(1, $tpl2comps);$this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get('id'))));$this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get('id'))));$this->assertEquals(2, \core_competency\plan_competency::count_records(array('planid' => $plan1->get('id'))));$this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get('id'))));$this->assertFalse($plan1->is_based_on_template());$this->assertEquals($tpl1->get('id'), $plan1->get('origtemplateid'));$this->assertTrue($plan2->is_based_on_template());$this->assertEquals(null, $plan2->get('origtemplateid'));// Check we can unlink draft plan.try {api::unlink_plan_from_template($plan2);} catch (\coding_exception $e) {$this->fail('Fail to unlink draft plan.');}// Check we can not unlink completed plan.try {api::unlink_plan_from_template($plan3);$this->fail('We can not unlink completed plan.');} catch (\coding_exception $e) {// All good.}// Even the order remains.$plan1comps = \core_competency\plan_competency::list_competencies($plan1->get('id'));$before = reset($tpl1comps);$after = reset($plan1comps);$this->assertEquals($before->get('id'), $after->get('id'));$this->assertEquals($before->get('sortorder'), $after->get('sortorder'));$before = next($tpl1comps);$after = next($plan1comps);$this->assertEquals($before->get('id'), $after->get('id'));$this->assertEquals($before->get('sortorder'), $after->get('sortorder'));}public function test_update_template_updates_plans(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$u1 = $dg->create_user();$u2 = $dg->create_user();$lpg = $dg->get_plugin_generator('core_competency');$tpl1 = $lpg->create_template();$tpl2 = $lpg->create_template();// Create plans with data not matching templates.$time = time();$plan1 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $u1->id,'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_MARKDOWN));$plan2 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $u2->id,'name' => 'Not right name', 'duedate' => $time + 3601, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));$plan3 = $lpg->create_plan(array('templateid' => $tpl2->get('id'), 'userid' => $u1->id,'name' => 'Not sweet name', 'duedate' => $time + 3602, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));// Prepare our expectations.$plan1->read();$plan2->read();$plan3->read();$this->assertEquals($tpl1->get('id'), $plan1->get('templateid'));$this->assertEquals($tpl1->get('id'), $plan2->get('templateid'));$this->assertEquals($tpl2->get('id'), $plan3->get('templateid'));$this->assertNotEquals($tpl1->get('shortname'), $plan1->get('name'));$this->assertNotEquals($tpl1->get('shortname'), $plan2->get('name'));$this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));$this->assertNotEquals($tpl1->get('description'), $plan1->get('description'));$this->assertNotEquals($tpl1->get('description'), $plan2->get('description'));$this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));$this->assertNotEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));$this->assertNotEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));$this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));$this->assertNotEquals($tpl1->get('duedate'), $plan1->get('duedate'));$this->assertNotEquals($tpl1->get('duedate'), $plan2->get('duedate'));$this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));// Update the template without changing critical fields does not update the plans.$data = $tpl1->to_record();$data->visible = 0;api::update_template($data);$this->assertNotEquals($tpl1->get('shortname'), $plan1->get('name'));$this->assertNotEquals($tpl1->get('shortname'), $plan2->get('name'));$this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));$this->assertNotEquals($tpl1->get('description'), $plan1->get('description'));$this->assertNotEquals($tpl1->get('description'), $plan2->get('description'));$this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));$this->assertNotEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));$this->assertNotEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));$this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));$this->assertNotEquals($tpl1->get('duedate'), $plan1->get('duedate'));$this->assertNotEquals($tpl1->get('duedate'), $plan2->get('duedate'));$this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));// Now really update the template.$data = $tpl1->to_record();$data->shortname = 'Awesome!';$data->description = 'This is too awesome!';$data->descriptionformat = FORMAT_HTML;$data->duedate = $time + 200;api::update_template($data);$tpl1->read();// Now confirm that the right plans were updated.$plan1->read();$plan2->read();$plan3->read();$this->assertEquals($tpl1->get('id'), $plan1->get('templateid'));$this->assertEquals($tpl1->get('id'), $plan2->get('templateid'));$this->assertEquals($tpl2->get('id'), $plan3->get('templateid'));$this->assertEquals($tpl1->get('shortname'), $plan1->get('name'));$this->assertEquals($tpl1->get('shortname'), $plan2->get('name'));$this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));$this->assertEquals($tpl1->get('description'), $plan1->get('description'));$this->assertEquals($tpl1->get('description'), $plan2->get('description'));$this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));$this->assertEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));$this->assertEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));$this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));$this->assertEquals($tpl1->get('duedate'), $plan1->get('duedate'));$this->assertEquals($tpl1->get('duedate'), $plan2->get('duedate'));$this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));}/*** Test that the method to complete a plan.*/public function test_complete_plan(): void {global $DB;$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$user = $dg->create_user();// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create two plans and assign competencies.$plan = $lpg->create_plan(array('userid' => $user->id));$otherplan = $lpg->create_plan(array('userid' => $user->id));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));$lpg->create_plan_competency(array('planid' => $otherplan->get('id'), 'competencyid' => $c1->get('id')));$uclist = array($lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id'),'proficiency' => true, 'grade' => 1 )),$lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id'),'proficiency' => false, 'grade' => 2 )));$this->assertEquals(2, \core_competency\user_competency::count_records());$this->assertEquals(0, \core_competency\user_competency_plan::count_records());// Change status of the plan to complete.api::complete_plan($plan);// Check that user competencies are now in user_competency_plan objects and still in user_competency.$this->assertEquals(2, \core_competency\user_competency::count_records());$this->assertEquals(3, \core_competency\user_competency_plan::count_records());$usercompetenciesplan = \core_competency\user_competency_plan::get_records();$this->assertEquals($uclist[0]->get('userid'), $usercompetenciesplan[0]->get('userid'));$this->assertEquals($uclist[0]->get('competencyid'), $usercompetenciesplan[0]->get('competencyid'));$this->assertEquals($uclist[0]->get('proficiency'), (bool) $usercompetenciesplan[0]->get('proficiency'));$this->assertEquals($uclist[0]->get('grade'), $usercompetenciesplan[0]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[0]->get('planid'));$this->assertEquals($uclist[1]->get('userid'), $usercompetenciesplan[1]->get('userid'));$this->assertEquals($uclist[1]->get('competencyid'), $usercompetenciesplan[1]->get('competencyid'));$this->assertEquals($uclist[1]->get('proficiency'), (bool) $usercompetenciesplan[1]->get('proficiency'));$this->assertEquals($uclist[1]->get('grade'), $usercompetenciesplan[1]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[1]->get('planid'));$this->assertEquals($user->id, $usercompetenciesplan[2]->get('userid'));$this->assertEquals($c3->get('id'), $usercompetenciesplan[2]->get('competencyid'));$this->assertNull($usercompetenciesplan[2]->get('proficiency'));$this->assertNull($usercompetenciesplan[2]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[2]->get('planid'));// Check we can not add competency to completed plan.try {api::add_competency_to_plan($plan->get('id'), $c4->get('id'));$this->fail('We can not add competency to completed plan.');} catch (\coding_exception $e) {// All good.}// Check we can not remove competency to completed plan.try {api::remove_competency_from_plan($plan->get('id'), $c3->get('id'));$this->fail('We can not remove competency to completed plan.');} catch (\coding_exception $e) {// All good.}// Completing a plan that is completed throws an exception.$this->expectException(\coding_exception::class);api::complete_plan($plan);}/*** Set-up the workflow data (review, active, ...).** @return array*/protected function setup_workflow_data() {$this->resetAfterTest();$dg = $this->getDataGenerator();$user = $dg->create_user();$reviewer = $dg->create_user();$otheruser = $dg->create_user();$syscontext = \context_system::instance();$userrole = $dg->create_role();$reviewerrole = $dg->create_role();$otheruserrole = $dg->create_role();assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $userrole, $syscontext->id);assign_capability('moodle/competency:planmanage', CAP_ALLOW, $reviewerrole, $syscontext->id);assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $reviewerrole, $syscontext->id);$dg->role_assign($userrole, $user->id, $syscontext->id);$dg->role_assign($reviewerrole, $reviewer->id, $syscontext->id);accesslib_clear_all_caches_for_unit_testing();$lpg = $dg->get_plugin_generator('core_competency');$tpl = $lpg->create_template();$plan = $lpg->create_plan(array('userid' => $user->id));$tplplan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tpl->get('id')));return array('dg' => $dg,'lpg' => $lpg,'user' => $user,'reviewer' => $reviewer,'otheruser' => $otheruser,'plan' => $plan,'tplplan' => $tplplan,);}/*** Testing requesting the review of a plan.*/public function test_plan_request_review(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));$this->assertEquals(plan::STATUS_DRAFT, $tplplan->get('status'));// Foreign user cannot do anything.$this->setUser($otheruser);try {api::plan_request_review($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($user);try {api::plan_request_review($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans cannot be reviewed./', $e->getMessage());}// Can not send for review when not draft.$this->setUser($user);$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);try {api::plan_request_review($plan);$this->fail('The plan cannot be sent for review at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent for review at this stage./', $e->getMessage());}// Can not send for review when not draft.$this->setUser($user);$plan->set('status', plan::STATUS_ACTIVE);try {api::plan_request_review($plan);$this->fail('The plan cannot be sent for review at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent for review at this stage./', $e->getMessage());}// Can not send for review when not draft.$this->setUser($user);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::plan_request_review($plan);$this->fail('The plan cannot be sent for review at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent for review at this stage./', $e->getMessage());}// Can not send for review when not draft.$this->setUser($user);$plan->set('status', plan::STATUS_COMPLETE);try {api::plan_request_review($plan);$this->fail('The plan cannot be sent for review at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent for review at this stage./', $e->getMessage());}// Sending for review as a reviewer.$this->setUser($reviewer);$plan->set('status', plan::STATUS_DRAFT);try {api::plan_request_review($plan);$this->fail('The user can not request a review.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Sending for review.$this->setUser($user);api::plan_request_review($plan);$plan->read();$this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get('status'));// Sending for review by ID.$plan->set('status', plan::STATUS_DRAFT);$plan->update();api::plan_request_review($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get('status'));}/*** Testing cancelling the review request.*/public function test_plan_cancel_review_request(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];// Set waiting for review.$tplplan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$tplplan->update();$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$plan->update();// Foreign user cannot do anything.$this->setUser($otheruser);try {api::plan_cancel_review_request($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($user);try {api::plan_cancel_review_request($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans cannot be reviewed./', $e->getMessage());}// Can not cancel review request when not waiting for review.$this->setUser($user);$plan->set('status', plan::STATUS_DRAFT);try {api::plan_cancel_review_request($plan);$this->fail('The plan cannot be sent for review at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be cancelled at this stage./', $e->getMessage());}// Can not cancel review request when not waiting for review.$this->setUser($user);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::plan_cancel_review_request($plan);$this->fail('The plan review cannot be cancelled at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be cancelled at this stage./', $e->getMessage());}// Can not cancel review request when not waiting for review.$this->setUser($user);$plan->set('status', plan::STATUS_ACTIVE);try {api::plan_cancel_review_request($plan);$this->fail('The plan review cannot be cancelled at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be cancelled at this stage./', $e->getMessage());}// Can not cancel review request when not waiting for review.$this->setUser($user);$plan->set('status', plan::STATUS_COMPLETE);try {api::plan_cancel_review_request($plan);$this->fail('The plan review cannot be cancelled at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be cancelled at this stage./', $e->getMessage());}// Cancelling as a reviewer.$this->setUser($reviewer);$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);try {api::plan_cancel_review_request($plan);$this->fail('The user can not cancel a review request.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Cancelling review request.$this->setUser($user);api::plan_cancel_review_request($plan);$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));// Cancelling review request by ID.$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$plan->update();api::plan_cancel_review_request($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));}/*** Testing starting the review.*/public function test_plan_start_review(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];// Set waiting for review.$tplplan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$tplplan->update();$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$plan->update();// Foreign user cannot do anything.$this->setUser($otheruser);try {api::plan_start_review($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($reviewer);try {api::plan_start_review($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans cannot be reviewed./', $e->getMessage());}// Can not start a review when not waiting for review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_DRAFT);try {api::plan_start_review($plan);$this->fail('The plan review cannot be started at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be started at this stage./', $e->getMessage());}// Can not start a review when not waiting for review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::plan_start_review($plan);$this->fail('The plan review cannot be started at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be started at this stage./', $e->getMessage());}// Can not start a review when not waiting for review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_ACTIVE);try {api::plan_start_review($plan);$this->fail('The plan review cannot be started at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be started at this stage./', $e->getMessage());}// Can not start a review when not waiting for review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_COMPLETE);try {api::plan_start_review($plan);$this->fail('The plan review cannot be started at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be started at this stage./', $e->getMessage());}// Starting as the owner.$this->setUser($user);$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);try {api::plan_start_review($plan);$this->fail('The user can not start a review.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Starting review.$this->setUser($reviewer);api::plan_start_review($plan);$plan->read();$this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get('status'));$this->assertEquals($reviewer->id, $plan->get('reviewerid'));// Starting review by ID.$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$plan->set('reviewerid', null);$plan->update();api::plan_start_review($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get('status'));$this->assertEquals($reviewer->id, $plan->get('reviewerid'));}/*** Testing stopping the review.*/public function test_plan_stop_review(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];// Set waiting for review.$tplplan->set('status', plan::STATUS_IN_REVIEW);$tplplan->update();$plan->set('status', plan::STATUS_IN_REVIEW);$plan->update();// Foreign user cannot do anything.$this->setUser($otheruser);try {api::plan_stop_review($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($reviewer);try {api::plan_stop_review($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans cannot be reviewed./', $e->getMessage());}// Can not stop a review whe not in review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_DRAFT);try {api::plan_stop_review($plan);$this->fail('The plan review cannot be stopped at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be stopped at this stage./', $e->getMessage());}// Can not stop a review whe not in review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);try {api::plan_stop_review($plan);$this->fail('The plan review cannot be stopped at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be stopped at this stage./', $e->getMessage());}// Can not stop a review whe not in review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_ACTIVE);try {api::plan_stop_review($plan);$this->fail('The plan review cannot be stopped at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be stopped at this stage./', $e->getMessage());}// Can not stop a review whe not in review.$this->setUser($reviewer);$plan->set('status', plan::STATUS_COMPLETE);try {api::plan_stop_review($plan);$this->fail('The plan review cannot be stopped at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan review cannot be stopped at this stage./', $e->getMessage());}// Stopping as the owner.$this->setUser($user);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::plan_stop_review($plan);$this->fail('The user can not stop a review.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Stopping review.$this->setUser($reviewer);api::plan_stop_review($plan);$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));// Stopping review by ID.$plan->set('status', plan::STATUS_IN_REVIEW);$plan->update();api::plan_stop_review($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));}/*** Testing approving the plan.*/public function test_approve_plan(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];// Set waiting for review.$tplplan->set('status', plan::STATUS_IN_REVIEW);$tplplan->update();$plan->set('status', plan::STATUS_IN_REVIEW);$plan->update();// Foreign user cannot do anything.$this->setUser($otheruser);try {api::approve_plan($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($reviewer);try {api::approve_plan($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans are already approved./', $e->getMessage());}// Can not approve a plan already approved.$this->setUser($reviewer);$plan->set('status', plan::STATUS_ACTIVE);try {api::approve_plan($plan);$this->fail('The plan cannot be approved at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be approved at this stage./', $e->getMessage());}// Can not approve a plan already approved.$this->setUser($reviewer);$plan->set('status', plan::STATUS_COMPLETE);try {api::approve_plan($plan);$this->fail('The plan cannot be approved at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be approved at this stage./', $e->getMessage());}// Approve as the owner.$this->setUser($user);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::approve_plan($plan);$this->fail('The user can not approve the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Approve plan from in review.$this->setUser($reviewer);api::approve_plan($plan);$plan->read();$this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));// Approve plan by ID.$plan->set('status', plan::STATUS_IN_REVIEW);$plan->update();api::approve_plan($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));// Approve plan from draft.$plan->set('status', plan::STATUS_DRAFT);$plan->update();api::approve_plan($plan);$plan->read();$this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));// Approve plan from waiting for review.$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);$plan->update();api::approve_plan($plan);$plan->read();$this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));}/*** Testing stopping the review.*/public function test_unapprove_plan(): void {$data = $this->setup_workflow_data();$dg = $data['dg'];$lpg = $data['lpg'];$user = $data['user'];$reviewer = $data['reviewer'];$otheruser = $data['otheruser'];$plan = $data['plan'];$tplplan = $data['tplplan'];// Set waiting for review.$tplplan->set('status', plan::STATUS_ACTIVE);$tplplan->update();$plan->set('status', plan::STATUS_ACTIVE);$plan->update();// Foreign user cannot do anything.$this->setUser($otheruser);try {api::unapprove_plan($plan);$this->fail('The user can not read the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Can not change a plan based on a template.$this->setUser($reviewer);try {api::unapprove_plan($tplplan);$this->fail('The plan is based on a template.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/Template plans are always approved./', $e->getMessage());}// Can not unapprove a non-draft plan.$this->setUser($reviewer);$plan->set('status', plan::STATUS_DRAFT);try {api::unapprove_plan($plan);$this->fail('The plan cannot be sent back to draft at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent back to draft at this stage./', $e->getMessage());}// Can not unapprove a non-draft plan.$this->setUser($reviewer);$plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);try {api::unapprove_plan($plan);$this->fail('The plan cannot be sent back to draft at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent back to draft at this stage./', $e->getMessage());}// Can not unapprove a non-draft plan.$this->setUser($reviewer);$plan->set('status', plan::STATUS_IN_REVIEW);try {api::unapprove_plan($plan);$this->fail('The plan cannot be sent back to draft at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent back to draft at this stage./', $e->getMessage());}// Can not unapprove a non-draft plan.$this->setUser($reviewer);$plan->set('status', plan::STATUS_COMPLETE);try {api::unapprove_plan($plan);$this->fail('The plan cannot be sent back to draft at this stage.');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/The plan cannot be sent back to draft at this stage./', $e->getMessage());}// Unapprove as the owner.$this->setUser($user);$plan->set('status', plan::STATUS_ACTIVE);try {api::unapprove_plan($plan);$this->fail('The user can not unapprove the plan.');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Unapprove plan.$this->setUser($reviewer);api::unapprove_plan($plan);$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));// Unapprove plan by ID.$plan->set('status', plan::STATUS_ACTIVE);$plan->update();api::unapprove_plan($plan->get('id'));$plan->read();$this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));}/*** Test update plan and the managing of archived user competencies.*/public function test_update_plan_manage_archived_competencies(): void {global $DB;$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create users and roles for the test.$user = $dg->create_user();$manageownrole = $dg->create_role(array('name' => 'User manage own','shortname' => 'manageown'));assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);$dg->role_assign($manageownrole, $user->id, $syscontext->id);$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create two plans and assign competencies.$plan = $lpg->create_plan(array('userid' => $user->id));$otherplan = $lpg->create_plan(array('userid' => $user->id));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));$lpg->create_plan_competency(array('planid' => $otherplan->get('id'), 'competencyid' => $c1->get('id')));$uclist = array($lpg->create_user_competency(array('userid' => $user->id,'competencyid' => $c1->get('id'),'proficiency' => true,'grade' => 1)),$lpg->create_user_competency(array('userid' => $user->id,'competencyid' => $c2->get('id'),'proficiency' => false,'grade' => 2)));// Change status of the plan to complete.$record = $plan->to_record();$record->status = \core_competency\plan::STATUS_COMPLETE;try {$plan = api::update_plan($record);$this->fail('We cannot complete a plan using api::update_plan().');} catch (\coding_exception $e) {// All good.}api::complete_plan($plan);// Check that user compretencies are now in user_competency_plan objects and still in user_competency.$this->assertEquals(2, \core_competency\user_competency::count_records());$this->assertEquals(3, \core_competency\user_competency_plan::count_records());$usercompetenciesplan = \core_competency\user_competency_plan::get_records();$this->assertEquals($uclist[0]->get('userid'), $usercompetenciesplan[0]->get('userid'));$this->assertEquals($uclist[0]->get('competencyid'), $usercompetenciesplan[0]->get('competencyid'));$this->assertEquals($uclist[0]->get('proficiency'), (bool) $usercompetenciesplan[0]->get('proficiency'));$this->assertEquals($uclist[0]->get('grade'), $usercompetenciesplan[0]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[0]->get('planid'));$this->assertEquals($uclist[1]->get('userid'), $usercompetenciesplan[1]->get('userid'));$this->assertEquals($uclist[1]->get('competencyid'), $usercompetenciesplan[1]->get('competencyid'));$this->assertEquals($uclist[1]->get('proficiency'), (bool) $usercompetenciesplan[1]->get('proficiency'));$this->assertEquals($uclist[1]->get('grade'), $usercompetenciesplan[1]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[1]->get('planid'));$this->assertEquals($user->id, $usercompetenciesplan[2]->get('userid'));$this->assertEquals($c3->get('id'), $usercompetenciesplan[2]->get('competencyid'));$this->assertNull($usercompetenciesplan[2]->get('proficiency'));$this->assertNull($usercompetenciesplan[2]->get('grade'));$this->assertEquals($plan->get('id'), $usercompetenciesplan[2]->get('planid'));// Change status of the plan to active.$record = $plan->to_record();$record->status = \core_competency\plan::STATUS_ACTIVE;try {api::update_plan($record);$this->fail('Completed plan can not be edited');} catch (\coding_exception $e) {// All good.}api::reopen_plan($record->id);// Check that user_competency_plan objects are deleted if the plan status is changed to another status.$this->assertEquals(2, \core_competency\user_competency::count_records());$this->assertEquals(0, \core_competency\user_competency_plan::count_records());}/*** Test completing plan does not change the order of competencies.*/public function test_complete_plan_doesnot_change_order(): void {global $DB;$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create users and roles for the test.$user = $dg->create_user();// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create two plans and assign competencies.$plan = $lpg->create_plan(array('userid' => $user->id));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));$lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));// Changing competencies order in plan competency.api::reorder_plan_competency($plan->get('id'), $c1->get('id'), $c3->get('id'));$competencies = api::list_plan_competencies($plan);$this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));$this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));$this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));// Completing plan.api::complete_plan($plan);$competencies = api::list_plan_competencies($plan);// Completing plan does not change order.$this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));$this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));$this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));// Testing plan based on template.$template = $lpg->create_template();$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $c1->get('id')));$lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $c2->get('id')));$lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $c3->get('id')));// Reorder competencies in template.api::reorder_template_competency($template->get('id'), $c1->get('id'), $c3->get('id'));// Create plan from template.$plan = api::create_plan_from_template($template->get('id'), $user->id);$competencies = api::list_plan_competencies($plan);// Completing plan does not change order.$this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));$this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));$this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));// Completing plan.api::complete_plan($plan);$competencies = api::list_plan_competencies($plan);// Completing plan does not change order.$this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));$this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));$this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));}/*** Test remove plan and the managing of archived user competencies.*/public function test_delete_plan_manage_archived_competencies(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create user and role for the test.$user = $dg->create_user();$managerole = $dg->create_role(array('name' => 'User manage own','shortname' => 'manageown'));assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $managerole, $syscontext->id);assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $managerole, $syscontext->id);$dg->role_assign($managerole, $user->id, $syscontext->id);$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create completed plan with records in user_competency.$completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));$lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c2->get('id')));$uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));$uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id')));$ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get('id'),'planid' => $completedplan->get('id')));$ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get('id'),'planid' => $completedplan->get('id')));api::delete_plan($completedplan->get('id'));// Check that achived user competencies are deleted.$this->assertEquals(0, \core_competency\plan::count_records());$this->assertEquals(2, \core_competency\user_competency::count_records());$this->assertEquals(0, \core_competency\user_competency_plan::count_records());}/*** Test listing of plan competencies.*/public function test_list_plan_competencies_manage_archived_competencies(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create user and role for the test.$user = $dg->create_user();$viewrole = $dg->create_role(array('name' => 'User view','shortname' => 'view'));assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $viewrole, $syscontext->id);assign_capability('moodle/competency:planview', CAP_ALLOW, $viewrole, $syscontext->id);$dg->role_assign($viewrole, $user->id, $syscontext->id);$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create draft plan with records in user_competency.$draftplan = $lpg->create_plan(array('userid' => $user->id));$lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c2->get('id')));$lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c3->get('id')));$uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));$uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id')));// Check that user_competency objects are returned when plan status is not complete.$plancompetencies = api::list_plan_competencies($draftplan);$this->assertCount(3, $plancompetencies);$this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[0]->usercompetency);$this->assertEquals($uc1->get('id'), $plancompetencies[0]->usercompetency->get('id'));$this->assertNull($plancompetencies[0]->usercompetencyplan);$this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[1]->usercompetency);$this->assertEquals($uc2->get('id'), $plancompetencies[1]->usercompetency->get('id'));$this->assertNull($plancompetencies[1]->usercompetencyplan);$this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[2]->usercompetency);$this->assertEquals(0, $plancompetencies[2]->usercompetency->get('id'));$this->assertNull($plancompetencies[2]->usercompetencyplan);// Create completed plan with records in user_competency_plan.$completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));$pc1 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c1->get('id')));$pc2 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c2->get('id')));$pc3 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c3->get('id')));$ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get('id'),'planid' => $completedplan->get('id')));$ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get('id'),'planid' => $completedplan->get('id')));$ucp3 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c3->get('id'),'planid' => $completedplan->get('id')));// Check that user_competency_plan objects are returned when plan status is complete.$plancompetencies = api::list_plan_competencies($completedplan);$this->assertCount(3, $plancompetencies);$this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[0]->usercompetencyplan);$this->assertEquals($ucp1->get('id'), $plancompetencies[0]->usercompetencyplan->get('id'));$this->assertNull($plancompetencies[0]->usercompetency);$this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[1]->usercompetencyplan);$this->assertEquals($ucp2->get('id'), $plancompetencies[1]->usercompetencyplan->get('id'));$this->assertNull($plancompetencies[1]->usercompetency);$this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[2]->usercompetencyplan);$this->assertEquals($ucp3->get('id'), $plancompetencies[2]->usercompetencyplan->get('id'));$this->assertNull($plancompetencies[2]->usercompetency);}public function test_create_template_cohort(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$c1 = $dg->create_cohort();$c2 = $dg->create_cohort();$t1 = $lpg->create_template();$t2 = $lpg->create_template();$this->assertEquals(0, \core_competency\template_cohort::count_records());// Create two relations with mixed parameters.$result = api::create_template_cohort($t1->get('id'), $c1->id);$result = api::create_template_cohort($t1, $c2);$this->assertEquals(2, \core_competency\template_cohort::count_records());$this->assertInstanceOf('core_competency\template_cohort', $result);$this->assertEquals($c2->id, $result->get('cohortid'));$this->assertEquals($t1->get('id'), $result->get('templateid'));$this->assertEquals(2, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t1->get('id'))));$this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t2->get('id'))));}public function test_create_template_cohort_permissions(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$cat = $dg->create_category();$catcontext = \context_coursecat::instance($cat->id);$syscontext = \context_system::instance();$user = $dg->create_user();$role = $dg->create_role();assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);$dg->role_assign($role, $user->id, $syscontext->id);$cohortrole = $dg->create_role();assign_capability('moodle/cohort:view', CAP_ALLOW, $cohortrole, $syscontext->id, true);accesslib_clear_all_caches_for_unit_testing();$c1 = $dg->create_cohort();$c2 = $dg->create_cohort(array('visible' => 0, 'contextid' => $catcontext->id));$t1 = $lpg->create_template();$this->assertEquals(0, \core_competency\template_cohort::count_records());$this->setUser($user);$result = api::create_template_cohort($t1, $c1);$this->assertInstanceOf('core_competency\\template_cohort', $result);try {$result = api::create_template_cohort($t1, $c2);$this->fail('Permission required.');} catch (\required_capability_exception $e) {// That's what should happen.}// Try again with the right permissions.$dg->role_assign($cohortrole, $user->id, $catcontext->id);accesslib_clear_all_caches_for_unit_testing();$result = api::create_template_cohort($t1, $c2);$this->assertInstanceOf('core_competency\\template_cohort', $result);}public function test_reorder_template_competencies_permissions(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$cat = $dg->create_category();$catcontext = \context_coursecat::instance($cat->id);$syscontext = \context_system::instance();$user = $dg->create_user();$role = $dg->create_role();assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);$dg->role_assign($role, $user->id, $syscontext->id);// Create a template.$template = $lpg->create_template(array('contextid' => $catcontext->id));// Create a competency framework.$framework = $lpg->create_framework(array('contextid' => $catcontext->id));// Create competencies.$competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Add the competencies.$lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $competency1->get('id')));$lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $competency2->get('id')));$this->setUser($user);// Can reorder competencies with system context permissions in category context.$result = api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));$this->assertTrue($result);unassign_capability('moodle/competency:templatemanage', $role, $syscontext->id);accesslib_clear_all_caches_for_unit_testing();try {api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));$this->fail('Exception expected due to not permissions to manage template competencies');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}// Giving permissions in category context.assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $catcontext->id, true);$dg->role_assign($role, $user->id, $catcontext->id);// User with templatemanage capability in category context can reorder competencies in temple.$result = api::reorder_template_competency($template->get('id'), $competency1->get('id'), $competency2->get('id'));$this->assertTrue($result);// Removing templatemanage capability in category context.unassign_capability('moodle/competency:templatemanage', $role, $catcontext->id);accesslib_clear_all_caches_for_unit_testing();try {api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));$this->fail('Exception expected due to not permissions to manage template competencies');} catch (\required_capability_exception $e) {$this->assertEquals('nopermissions', $e->errorcode);}}public function test_delete_template(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$c1 = $dg->create_cohort();$c2 = $dg->create_cohort();$template = $lpg->create_template();$id = $template->get('id');// Create 2 template cohorts.$tc1 = $lpg->create_template_cohort(array('templateid' => $template->get('id'), 'cohortid' => $c1->id));$tc1 = $lpg->create_template_cohort(array('templateid' => $template->get('id'), 'cohortid' => $c2->id));// Check pre-test.$this->assertTrue(\core_competency\template::record_exists($id));$this->assertEquals(2, \core_competency\template_cohort::count_records(array('templateid' => $id)));$result = api::delete_template($template->get('id'));$this->assertTrue($result);// Check that the template deos not exist anymore.$this->assertFalse(\core_competency\template::record_exists($id));// Test if associated cohorts are also deleted.$this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $id)));}public function test_delete_template_cohort(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$c1 = $dg->create_cohort();$c2 = $dg->create_cohort();$t1 = $lpg->create_template();$t2 = $lpg->create_template();$tc1 = $lpg->create_template_cohort(array('templateid' => $t1->get('id'), 'cohortid' => $c1->id));$tc1 = $lpg->create_template_cohort(array('templateid' => $t2->get('id'), 'cohortid' => $c2->id));$this->assertEquals(2, \core_competency\template_cohort::count_records());$this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t1->get('id'))));$this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t2->get('id'))));// Delete existing.$result = api::delete_template_cohort($t1->get('id'), $c1->id);$this->assertTrue($result);$this->assertEquals(1, \core_competency\template_cohort::count_records());$this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t1->get('id'))));$this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t2->get('id'))));// Delete non-existant.$result = api::delete_template_cohort($t1->get('id'), $c1->id);$this->assertTrue($result);$this->assertEquals(1, \core_competency\template_cohort::count_records());$this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t1->get('id'))));$this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',array('id' => $t2->get('id'))));}public function test_add_evidence_log(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u1ctx = \context_user::instance($u1->id);$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));// Creating a standard evidence with minimal information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG,'invaliddata', 'error');$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertSame(null, $uc->get('grade'));$this->assertSame(null, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertSame(null, $evidence->get('grade'));$this->assertSame(null, $evidence->get('actionuserid'));// Creating a standard evidence with more information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', '$a', false, 'http://moodle.org', null, 2, 'The evidence of prior learning were reviewed.');$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertSame(null, $uc->get('grade'));$this->assertSame(null, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertEquals('$a', $evidence->get('desca'));$this->assertEquals('http://moodle.org', $evidence->get('url'));$this->assertSame(null, $evidence->get('grade'));$this->assertEquals(2, $evidence->get('actionuserid'));$this->assertSame('The evidence of prior learning were reviewed.', $evidence->get('note'));// Creating a standard evidence and send for review.$evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', null, true);$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));// Trying to pass a grade should fail.try {$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', null, false, null, 1);$this->fail('A grade can not be set');} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/grade MUST NOT be set/', $e->getMessage());}}public function test_add_evidence_complete(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u1ctx = \context_user::instance($u1->id);$scale = $dg->create_scale(array('scale' => 'A,B,C,D'));$scaleconfig = array(array('scaleid' => $scale->id));$scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 1, 'proficient' => 0);$scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 1);$scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 0, 'proficient' => 1);$c2scaleconfig = array(array('scaleid' => $scale->id));$c2scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 0, 'proficient' => 1);$c2scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 0);$c2scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 1, 'proficient' => 1);$f1 = $lpg->create_framework(array('scaleid' => $scale->id, 'scaleconfiguration' => $scaleconfig));$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'scaleid' => $scale->id,'scaleconfiguration' => $c2scaleconfig));$c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));// Creating an evidence with minimal information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE,'invaliddata', 'error');$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertEquals(2, $uc->get('grade')); // The grade has been set automatically to the framework default.$this->assertEquals(0, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertEquals(2, $evidence->get('grade'));$this->assertSame(null, $evidence->get('actionuserid'));// Creating an evidence complete on competency with custom scale.$evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE,'invaliddata', 'error');$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertEquals(4, $uc->get('grade')); // The grade has been set automatically to the competency default.$this->assertEquals(true, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertEquals(4, $evidence->get('grade'));$this->assertSame(null, $evidence->get('actionuserid'));// Creating an evidence complete on a user competency with an existing grade.$uc = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c3->get('id'), 'grade' => 1,'proficiency' => 0));$this->assertEquals(1, $uc->get('grade'));$this->assertEquals(0, $uc->get('proficiency'));$evidence = api::add_evidence($u1->id, $c3->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE,'invaliddata', 'error');$evidence->read();$uc->read();$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertEquals(1, $uc->get('grade')); // The grade has not been changed.$this->assertEquals(0, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertEquals(2, $evidence->get('grade')); // The complete grade has been set.$this->assertSame(null, $evidence->get('actionuserid'));// Creating a standard evidence and send for review.$evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE,'invaliddata', 'error', null, true);$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));// Trying to pass a grade should throw an exception.try {api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata','error', null, false, null, 1);} catch (\coding_exception $e) {$this->assertMatchesRegularExpression('/grade MUST NOT be set/', $e->getMessage());}}public function test_add_evidence_override(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u1ctx = \context_user::instance($u1->id);$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));// Creating an evidence with minimal information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE,'invaliddata', 'error');$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertSame(null, $uc->get('grade')); // We overrode with 'null'.$this->assertSame(null, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertSame(null, $evidence->get('grade')); // We overrode with 'null'.$this->assertSame(null, $evidence->get('actionuserid'));// Creating an evidence with a grade information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE,'invaliddata', 'error', null, false, null, 3);$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertEquals(3, $uc->get('grade'));$this->assertEquals(true, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertEquals(3, $evidence->get('grade'));$this->assertSame(null, $evidence->get('actionuserid'));// Creating an evidence with another grade information.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE,'invaliddata', 'error', null, false, null, 1);$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));$this->assertEquals(1, $uc->get('grade'));$this->assertEquals(0, $uc->get('proficiency'));$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals($u1ctx->id, $evidence->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));$this->assertEquals('invaliddata', $evidence->get('descidentifier'));$this->assertEquals('error', $evidence->get('desccomponent'));$this->assertSame(null, $evidence->get('desca'));$this->assertSame(null, $evidence->get('url'));$this->assertEquals(1, $evidence->get('grade'));$this->assertSame(null, $evidence->get('actionuserid'));// Creating reverting the grade and send for review.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE,'invaliddata', 'error', null, true);$evidence->read();$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertSame(null, $uc->get('grade'));$this->assertSame(null, $uc->get('proficiency'));$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));$this->assertSame(null, $evidence->get('grade'));}public function test_add_evidence_and_send_for_review(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u1ctx = \context_user::instance($u1->id);$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));// Non-existing user competencies are created up for review.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', null, true);$uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));// Existing user competencies sent for review don't change.$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', null, true);$uc->read();$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));// A user competency with a status non-idle won't change.$uc->set('status', \core_competency\user_competency::STATUS_IN_REVIEW);$uc->update();$evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata','error', null, true);$uc->read();$this->assertEquals(\core_competency\user_competency::STATUS_IN_REVIEW, $uc->get('status'));}/*** Test add evidence for existing user_competency.*/public function test_add_evidence_existing_user_competency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create users.$user = $dg->create_user();$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$uc = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));$this->assertSame(null, $uc->get('grade'));$this->assertSame(null, $uc->get('proficiency'));// Create an evidence and check it was created with the right usercomptencyid and information.$evidence = api::add_evidence($user->id, $c1->get('id'), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,'invalidevidencedesc', 'core_competency', array('a' => 'b'), false, 'http://moodle.org', 1, 2);$this->assertEquals(1, \core_competency\evidence::count_records());$evidence->read();$uc->read();$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals('invalidevidencedesc', $evidence->get('descidentifier'));$this->assertEquals('core_competency', $evidence->get('desccomponent'));$this->assertEquals((object) array('a' => 'b'), $evidence->get('desca'));$this->assertEquals('http://moodle.org', $evidence->get('url'));$this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));$this->assertEquals(2, $evidence->get('actionuserid'));$this->assertEquals(1, $evidence->get('grade'));$this->assertEquals(1, $uc->get('grade'));$this->assertEquals(0, $uc->get('proficiency'));}/*** Test add evidence for non-existing user_competency.*/public function test_add_evidence_no_existing_user_competency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create users.$user = $dg->create_user();$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$this->assertEquals(0, \core_competency\user_competency::count_records());// Create an evidence without a user competency record.$evidence = api::add_evidence($user->id, $c1->get('id'), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,'invalidevidencedesc', 'core_competency', 'Hello world!', false, 'http://moodle.org', 1, 2);$this->assertEquals(1, \core_competency\evidence::count_records());$this->assertEquals(1, \core_competency\user_competency::count_records());$uc = \core_competency\user_competency::get_record(array('userid' => $user->id, 'competencyid' => $c1->get('id')));$evidence->read();$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));$this->assertEquals('invalidevidencedesc', $evidence->get('descidentifier'));$this->assertEquals('core_competency', $evidence->get('desccomponent'));$this->assertEquals('Hello world!', $evidence->get('desca'));$this->assertEquals('http://moodle.org', $evidence->get('url'));$this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));$this->assertEquals(2, $evidence->get('actionuserid'));$this->assertEquals(1, $evidence->get('grade'));$this->assertEquals(1, $uc->get('grade'));$this->assertEquals(0, $uc->get('proficiency'));}public function test_add_evidence_applies_competency_rules(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$syscontext = \context_system::instance();$ctxid = $syscontext->id;$u1 = $dg->create_user();// Setting up the framework.$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c2->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c3a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c3->get('id')));$c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c4a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c4->get('id')));$c5 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));// Setting up the rules.$c1->set('ruletype', 'core_competency\\competency_rule_all');$c1->set('ruleoutcome', \core_competency\competency::OUTCOME_COMPLETE);$c1->update();$c2->set('ruletype', 'core_competency\\competency_rule_all');$c2->set('ruleoutcome', \core_competency\competency::OUTCOME_RECOMMEND);$c2->update();$c3->set('ruletype', 'core_competency\\competency_rule_all');$c3->set('ruleoutcome', \core_competency\competency::OUTCOME_EVIDENCE);$c3->update();$c4->set('ruletype', 'core_competency\\competency_rule_all');$c4->set('ruleoutcome', \core_competency\competency::OUTCOME_NONE);$c4->update();// Confirm the current data.$this->assertEquals(0, user_competency::count_records());$this->assertEquals(0, evidence::count_records());// Let's do this!// First let's confirm that evidence not marking a completion have no impact.api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_LOG, 'commentincontext', 'core');$uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get('id')));$this->assertSame(null, $uc1a->get('proficiency'));$this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?',array($u1->id, $c1->get('id'))));// Now let's try complete a competency but the rule won't match (not all children are complete).// The parent (the thing with the rule) will be created but won't have any evidence attached, and not// not be marked as completed.api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');$uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get('id')));$this->assertEquals(true, $uc1a->get('proficiency'));$uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertSame(null, $uc1->get('proficiency'));$this->assertEquals(0, evidence::count_records(array('usercompetencyid' => $uc1->get('id'))));// Now we complete the other child. That will mark the parent as complete with an evidence.api::add_evidence($u1->id, $c1b, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');$uc1b = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1b->get('id')));$this->assertEquals(true, $uc1a->get('proficiency'));$uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));$this->assertEquals(true, $uc1->get('proficiency'));$this->assertEquals(user_competency::STATUS_IDLE, $uc1->get('status'));$this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc1->get('id'))));// Check rule recommending.api::add_evidence($u1->id, $c2a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');$uc2a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2a->get('id')));$this->assertEquals(true, $uc1a->get('proficiency'));$uc2 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));$this->assertSame(null, $uc2->get('proficiency'));$this->assertEquals(user_competency::STATUS_WAITING_FOR_REVIEW, $uc2->get('status'));$this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc2->get('id'))));// Check rule evidence.api::add_evidence($u1->id, $c3a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');$uc3a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3a->get('id')));$this->assertEquals(true, $uc1a->get('proficiency'));$uc3 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get('id')));$this->assertSame(null, $uc3->get('proficiency'));$this->assertEquals(user_competency::STATUS_IDLE, $uc3->get('status'));$this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc3->get('id'))));// Check rule nothing.api::add_evidence($u1->id, $c4a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');$uc4a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4a->get('id')));$this->assertEquals(true, $uc1a->get('proficiency'));$this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?',array($u1->id, $c4->get('id'))));// Check marking on something that has no parent. This just checks that nothing breaks.api::add_evidence($u1->id, $c5, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');}/*** Tests for the user_competency_course data when api::add_evidence() is invoked when* grading a user competency in the system context.*/public function test_add_evidence_for_user_competency_course_grade_outside_course(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$syscontext = \context_system::instance();// Create a student.$student = $dg->create_user();// Create a competency for the course.$lpg = $dg->get_plugin_generator('core_competency');$framework = $lpg->create_framework();$comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Add evidence.api::add_evidence($student->id, $comp, $syscontext, evidence::ACTION_OVERRIDE,'commentincontext', 'core', null, false, null, 1);// Query for user_competency_course data.$filterparams = array('userid' => $student->id,'competencyid' => $comp->get('id'),);$usercompcourse = \core_competency\user_competency_course::get_record($filterparams);// There should be no user_competency_course object created when grading.$this->assertFalse($usercompcourse);}/*** Tests for the user_competency_course data when api::add_evidence() is invoked when* grading a user competency in a course.*/public function test_add_evidence_user_competency_course_grade_in_course(): void {global $USER;$this->resetAfterTest(true);$dg = $this->getDataGenerator();// Create and assign a current user.$currentuser = $dg->create_user();$this->setUser($currentuser);// Create a course.$course = $dg->create_course();$record = array('courseid' => $course->id, 'pushratingstouserplans' => false);$settings = new course_competency_settings(0, (object) $record);$settings->create();$coursecontext = \context_course::instance($course->id);// Create a student and enrol into the course.$student = $dg->create_user();$studentarch = get_archetype_roles('student');$studentrole = array_shift($studentarch);$dg->role_assign($studentrole->id, $student->id, $coursecontext->id);$dg->enrol_user($student->id, $course->id, $studentrole->id);// Create a competency for the course.$lpg = $dg->get_plugin_generator('core_competency');$framework = $lpg->create_framework();// Do not push ratings from course to user plans.$comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$lpg->create_course_competency(array('courseid' => $course->id, 'competencyid' => $comp->get('id')));// Query for user_competency_course data.$filterparams = array('userid' => $student->id,'competencyid' => $comp->get('id'),'courseid' => $course->id);// Add evidence that sets a grade to the course.$evidence = api::add_evidence($student->id, $comp, $coursecontext, evidence::ACTION_OVERRIDE,'commentincontext', 'core', null, false, null, 3, $USER->id);// Get user competency course record.$usercompcourse = \core_competency\user_competency_course::get_record($filterparams);// There should be a user_competency_course object when adding a grade.$this->assertNotEmpty($usercompcourse);$grade = $evidence->get('grade');$this->assertEquals($grade, $usercompcourse->get('grade'));$this->assertEquals(3, $usercompcourse->get('grade'));$proficiency = $comp->get_proficiency_of_grade($grade);$this->assertEquals($proficiency, $usercompcourse->get('proficiency'));// Confirm that the user competency's grade/proficiency has not been affected by the grade.$usercompetencyparams = ['userid' => $student->id,'competencyid' => $comp->get('id'),];$usercompetency = \core_competency\user_competency::get_record($usercompetencyparams);$this->assertNotEmpty($usercompetency);$this->assertNotEquals($usercompcourse->get('grade'), $usercompetency->get('grade'));$this->assertNotEquals($usercompcourse->get('proficiency'), $usercompetency->get('proficiency'));}public function test_observe_course_completed(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');// Set-up users, framework, competencies and course competencies.$course = $dg->create_course();$coursectx = \context_course::instance($course->id);$u1 = $dg->create_user();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$cc1 = $lpg->create_course_competency(array('competencyid' => $c1->get('id'), 'courseid' => $course->id,'ruleoutcome' => \core_competency\course_competency::OUTCOME_NONE));$cc2 = $lpg->create_course_competency(array('competencyid' => $c2->get('id'), 'courseid' => $course->id,'ruleoutcome' => \core_competency\course_competency::OUTCOME_EVIDENCE));$cc3 = $lpg->create_course_competency(array('competencyid' => $c3->get('id'), 'courseid' => $course->id,'ruleoutcome' => \core_competency\course_competency::OUTCOME_RECOMMEND));$cc4 = $lpg->create_course_competency(array('competencyid' => $c4->get('id'), 'courseid' => $course->id,'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE));$event = \core\event\course_completed::create(array('objectid' => 1,'relateduserid' => $u1->id,'context' => $coursectx,'courseid' => $course->id,'other' => array('relateduserid' => $u1->id)));$this->assertEquals(0, \core_competency\user_competency::count_records());$this->assertEquals(0, \core_competency\evidence::count_records());// Let's go!api::observe_course_completed($event);$this->assertEquals(3, \core_competency\user_competency::count_records());$this->assertEquals(3, \core_competency\evidence::count_records());// Outcome NONE did nothing.$this->assertFalse(\core_competency\user_competency::record_exists_select('userid = :uid AND competencyid = :cid', array('uid' => $u1->id, 'cid' => $c1->get('id'))));// Outcome evidence.$uc2 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));$ev2 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc2->get('id')));$this->assertEquals(null, $uc2->get('grade'));$this->assertEquals(null, $uc2->get('proficiency'));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc2->get('status'));$this->assertEquals('evidence_coursecompleted', $ev2->get('descidentifier'));$this->assertEquals('core_competency', $ev2->get('desccomponent'));$this->assertEquals($course->shortname, $ev2->get('desca'));$this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev2->get('url'));$this->assertEquals(null, $ev2->get('grade'));$this->assertEquals($coursectx->id, $ev2->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev2->get('action'));$this->assertEquals(null, $ev2->get('actionuserid'));// Outcome recommend.$uc3 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get('id')));$ev3 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc3->get('id')));$this->assertEquals(null, $uc3->get('grade'));$this->assertEquals(null, $uc3->get('proficiency'));$this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc3->get('status'));$this->assertEquals('evidence_coursecompleted', $ev3->get('descidentifier'));$this->assertEquals('core_competency', $ev3->get('desccomponent'));$this->assertEquals($course->shortname, $ev3->get('desca'));$this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev3->get('url'));$this->assertEquals(null, $ev3->get('grade'));$this->assertEquals($coursectx->id, $ev3->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev3->get('action'));$this->assertEquals(null, $ev3->get('actionuserid'));// Outcome complete.$uc4 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4->get('id')));$ev4 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc4->get('id')));$this->assertEquals(3, $uc4->get('grade'));$this->assertEquals(1, $uc4->get('proficiency'));$this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc4->get('status'));$this->assertEquals('evidence_coursecompleted', $ev4->get('descidentifier'));$this->assertEquals('core_competency', $ev4->get('desccomponent'));$this->assertEquals($course->shortname, $ev4->get('desca'));$this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev4->get('url'));$this->assertEquals(3, $ev4->get('grade'));$this->assertEquals($coursectx->id, $ev4->get('contextid'));$this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $ev4->get('action'));$this->assertEquals(null, $ev4->get('actionuserid'));}public function test_list_evidence_in_course(): void {global $SITE;$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$course = $dg->create_course();$coursecontext = \context_course::instance($course->id);$this->setAdminUser();$f = $lpg->create_framework();$c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$cc = api::add_competency_to_course($course->id, $c->get('id'));$cc2 = api::add_competency_to_course($course->id, $c2->get('id'));$pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');$page = $pagegenerator->create_instance(array('course' => $course->id));$cm = get_coursemodule_from_instance('page', $page->id);$cmcontext = \context_module::instance($cm->id);// Add the competency to the course module.$ccm = api::add_competency_to_course_module($cm, $c->get('id'));// Now add the evidence to the course.$evidence1 = api::add_evidence($u1->id, $c->get('id'), $coursecontext->id, \core_competency\evidence::ACTION_LOG,'invaliddata', 'error');$result = api::list_evidence_in_course($u1->id, $course->id, $c->get('id'));$this->assertEquals($result[0]->get('id'), $evidence1->get('id'));// Now add the evidence to the course module.$evidence2 = api::add_evidence($u1->id, $c->get('id'), $cmcontext->id, \core_competency\evidence::ACTION_LOG,'invaliddata', 'error');$result = api::list_evidence_in_course($u1->id, $course->id, $c->get('id'), 'timecreated', 'ASC');$this->assertEquals($evidence1->get('id'), $result[0]->get('id'));$this->assertEquals($evidence2->get('id'), $result[1]->get('id'));}public function test_list_course_modules_using_competency(): void {global $SITE;$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u2 = $dg->create_user();$course = $dg->create_course();$course2 = $dg->create_course();$this->setAdminUser();$f = $lpg->create_framework();$c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$cc = api::add_competency_to_course($course->id, $c->get('id'));$cc2 = api::add_competency_to_course($course->id, $c2->get('id'));// First check we get an empty list when there are no links.$expected = array();$result = api::list_course_modules_using_competency($c->get('id'), $course->id);$this->assertEquals($expected, $result);$pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');$page = $pagegenerator->create_instance(array('course' => $course->id));$cm = get_coursemodule_from_instance('page', $page->id);// Add a link and list again.$ccm = api::add_competency_to_course_module($cm, $c->get('id'));$expected = array($cm->id);$result = api::list_course_modules_using_competency($c->get('id'), $course->id);$this->assertEquals($expected, $result);// Check a different course.$expected = array();$result = api::list_course_modules_using_competency($c->get('id'), $course2->id);$this->assertEquals($expected, $result);// Remove the link and check again.$result = api::remove_competency_from_course_module($cm, $c->get('id'));$expected = true;$this->assertEquals($expected, $result);$expected = array();$result = api::list_course_modules_using_competency($c->get('id'), $course->id);$this->assertEquals($expected, $result);// Now add 2 links.api::add_competency_to_course_module($cm, $c->get('id'));api::add_competency_to_course_module($cm, $c2->get('id'));$result = api::list_course_module_competencies_in_course_module($cm->id);$this->assertEquals($result[0]->get('competencyid'), $c->get('id'));$this->assertEquals($result[1]->get('competencyid'), $c2->get('id'));// Now re-order.api::reorder_course_module_competency($cm, $c->get('id'), $c2->get('id'));$result = api::list_course_module_competencies_in_course_module($cm->id);$this->assertEquals($result[0]->get('competencyid'), $c2->get('id'));$this->assertEquals($result[1]->get('competencyid'), $c->get('id'));// And re-order again.api::reorder_course_module_competency($cm, $c->get('id'), $c2->get('id'));$result = api::list_course_module_competencies_in_course_module($cm->id);$this->assertEquals($result[0]->get('competencyid'), $c->get('id'));$this->assertEquals($result[1]->get('competencyid'), $c2->get('id'));// Now get the course competency and coursemodule competency together.$result = api::list_course_module_competencies($cm->id);// Now we should have an array and each element of the array should have a competency and// a coursemodulecompetency.foreach ($result as $instance) {$cmc = $instance['coursemodulecompetency'];$c = $instance['competency'];$this->assertEquals($cmc->get('competencyid'), $c->get('id'));}}/*** Test update ruleoutcome for course_competency.*/public function test_set_ruleoutcome_course_competency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$u2 = $dg->create_user();$course = $dg->create_course();$this->setAdminUser();$f = $lpg->create_framework();$c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$cc = api::add_competency_to_course($course->id, $c->get('id'));// Check record was created with default rule value Evidence.$this->assertEquals(1, \core_competency\course_competency::count_records());$recordscc = api::list_course_competencies($course->id);$this->assertEquals(\core_competency\course_competency::OUTCOME_EVIDENCE,$recordscc[0]['coursecompetency']->get('ruleoutcome'));// Check ruleoutcome value is updated to None.$this->assertTrue(api::set_course_competency_ruleoutcome($recordscc[0]['coursecompetency']->get('id'),\core_competency\course_competency::OUTCOME_NONE));$recordscc = api::list_course_competencies($course->id);$this->assertEquals(\core_competency\course_competency::OUTCOME_NONE,$recordscc[0]['coursecompetency']->get('ruleoutcome'));}/*** Test validation on grade on user_competency.*/public function test_validate_grade_in_user_competency(): void {global $DB;$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$user = $dg->create_user();$s1 = $dg->create_scale(array("scale" => "value1, value2"));$s2 = $dg->create_scale(array("scale" => "value3, value4, value5, value6"));$scaleconfiguration1 = '[{"scaleid":"'.$s1->id.'"},{"name":"value1","id":1,"scaledefault":1,"proficient":0},' .'{"name":"value2","id":2,"scaledefault":0,"proficient":1}]';$scaleconfiguration2 = '[{"scaleid":"'.$s2->id.'"},{"name":"value3","id":1,"scaledefault":1,"proficient":0},'. '{"name":"value4","id":2,"scaledefault":0,"proficient":1}]';// Create a framework with scale configuration1.$frm = array('scaleid' => $s1->id,'scaleconfiguration' => $scaleconfiguration1);$framework = $lpg->create_framework($frm);$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create competency with its own scale configuration.$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),'scaleid' => $s2->id,'scaleconfiguration' => $scaleconfiguration2));// Detecte invalid grade in competency using its framework competency scale.try {$usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get('id'),'proficiency' => true, 'grade' => 3 ));$usercompetency->create();$this->fail('Invalid grade not detected in framework scale');} catch (\core\invalid_persistent_exception $e) {$this->assertTrue(true);}// Detecte invalid grade in competency using its own scale.try {$usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get('id'),'proficiency' => true, 'grade' => 5 ));$usercompetency->create();$this->fail('Invalid grade not detected in competency scale');} catch (\core\invalid_persistent_exception $e) {$this->assertTrue(true);}// Accept valid grade in competency using its framework competency scale.try {$usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get('id'),'proficiency' => true, 'grade' => 1 ));$usercompetency->create();$this->assertTrue(true);} catch (\core\invalid_persistent_exception $e) {$this->fail('Valide grade rejected in framework scale');}// Accept valid grade in competency using its framework competency scale.try {$usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get('id'),'proficiency' => true, 'grade' => 4 ));$usercompetency->create();$this->assertTrue(true);} catch (\core\invalid_persistent_exception $e) {$this->fail('Valide grade rejected in competency scale');}}/*** Test when adding competency that belong to hidden framework to plan/template/course.*/public function test_hidden_framework(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$user = $dg->create_user();// Create a course.$cat1 = $dg->create_category();$course = $dg->create_course(array('category' => $cat1->id));// Create a template.$template = $lpg->create_template();// Create a plan.$plan = $lpg->create_plan(array('userid' => $user->id));// Create a hidden framework.$frm = array('visible' => false);$framework = $lpg->create_framework($frm);$competency = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Linking competency that belong to hidden framework to course.try {api::add_competency_to_course($course->id, $competency->get('id'));$this->fail('A competency belonging to hidden framework can not be linked to course');} catch (\coding_exception $e) {$this->assertTrue(true);}// Adding competency that belong to hidden framework to template.try {api::add_competency_to_template($template->get('id'), $competency->get('id'));$this->fail('A competency belonging to hidden framework can not be added to template');} catch (\coding_exception $e) {$this->assertTrue(true);}// Adding competency that belong to hidden framework to plan.try {api::add_competency_to_plan($plan->get('id'), $competency->get('id'));$this->fail('A competency belonging to hidden framework can not be added to plan');} catch (\coding_exception $e) {$this->assertTrue(true);}}/*** Test when using hidden template in plan/cohort.*/public function test_hidden_template(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$user = $dg->create_user();// Create a cohort.$cohort = $dg->create_cohort();// Create a hidden template.$template = $lpg->create_template(array('visible' => false));// Can not link hidden template to plan.try {api::create_plan_from_template($template->get('id'), $user->id);$this->fail('Can not link a hidden template to plan');} catch (\coding_exception $e) {$this->assertTrue(true);}// Can associate hidden template to cohort.$templatecohort = api::create_template_cohort($template->get('id'), $cohort->id);$this->assertInstanceOf('\core_competency\template_cohort', $templatecohort);}/*** Test that completed plan created form a template does not change when template is modified.*/public function test_completed_plan_doesnot_change(): void {global $DB;$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$user = $dg->create_user();// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create template and assign competencies.$tp = $lpg->create_template();$tpc1 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c1->get('id')));$tpc2 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c2->get('id')));$tpc3 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c3->get('id')));// Create a plan form template and change it status to complete.$plan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tp->get('id')));api::complete_plan($plan);// Check user competency plan created correctly.$this->assertEquals(3, \core_competency\user_competency_plan::count_records());$ucp = \core_competency\user_competency_plan::get_records();$this->assertEquals($ucp[0]->get('competencyid'), $c1->get('id'));$this->assertEquals($ucp[1]->get('competencyid'), $c2->get('id'));$this->assertEquals($ucp[2]->get('competencyid'), $c3->get('id'));// Add and remove a competency from the template.api::add_competency_to_template($tp->get('id'), $c4->get('id'));api::remove_competency_from_template($tp->get('id'), $c1->get('id'));// Check that user competency plan did not change.$competencies = $plan->get_competencies();$this->assertEquals(3, count($competencies));$ucp1 = array($c1->get('id'), $c2->get('id'), $c3->get('id'));$ucp2 = array();foreach ($competencies as $id => $cmp) {$ucp2[] = $id;}$this->assertEquals(0, count(array_diff($ucp1, $ucp2)));}protected function setup_framework_for_reset_rules_tests() {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1a1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c1a1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1b1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c1b1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c1->set('ruletype', 'core_competency\\competency_rule_all');$c1->update();$c1a->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c1a->set('ruletype', 'core_competency\\competency_rule_all');$c1a->update();$c1a1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c1a1->set('ruletype', 'core_competency\\competency_rule_all');$c1a1->update();$c1b->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c1b->set('ruletype', 'core_competency\\competency_rule_all');$c1b->update();$c2->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c2->set('ruletype', 'core_competency\\competency_rule_all');$c2->update();return array('f1' => $f1,'c1' => $c1,'c1a' => $c1a,'c1a1' => $c1a1,'c1a1a' => $c1a1a,'c1b' => $c1b,'c1b1' => $c1b1,'c1b1a' => $c1b1a,'c2' => $c2,'c2a' => $c2a,);}public function test_moving_competency_reset_rules_updown(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Moving up and down doesn't change anything.api::move_down_competency($c1a->get('id'));$c1->read();$c1a->read();$c1a1->read();$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));api::move_up_competency($c1a->get('id'));$c1->read();$c1a->read();$c1a1->read();$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));}public function test_moving_competency_reset_rules_parent(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Moving out of parent will reset the parent, and the destination.api::set_parent_competency($c1a->get('id'), $c1b->get('id'));$c1->read();$c1a->read();$c1a1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_NONE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_moving_competency_reset_rules_totoplevel(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Moving to top level only affects the initial parent.api::set_parent_competency($c1a1->get('id'), 0);$c1->read();$c1a->read();$c1a1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_NONE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_moving_competency_reset_rules_fromtoplevel(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Moving from top level only affects the destination parent.api::set_parent_competency($c2->get('id'), $c1a1->get('id'));$c1->read();$c1a->read();$c1a1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_NONE, $c1a1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_moving_competency_reset_rules_child(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Moving to a child of self resets self, parent and destination.api::set_parent_competency($c1a->get('id'), $c1a1->get('id'));$c1->read();$c1a->read();$c1a1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_NONE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_NONE, $c1a1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_create_competency_reset_rules(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Adding a new competency resets the rule of its parent.api::create_competency((object) array('shortname' => 'A', 'parentid' => $c1->get('id'), 'idnumber' => 'A','competencyframeworkid' => $f1->get('id')));$c1->read();$c1a->read();$c1a1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_delete_competency_reset_rules(): void {$data = $this->setup_framework_for_reset_rules_tests();$f1 = $data['f1'];$c1 = $data['c1'];$c1a = $data['c1a'];$c1a1 = $data['c1a1'];$c1a1a = $data['c1a1a'];$c1b = $data['c1b'];$c1b1 = $data['c1b1'];$c1b1a = $data['c1b1a'];$c2 = $data['c2'];$c2a = $data['c2a'];// Deleting a competency resets the rule of its parent.api::delete_competency($c1a->get('id'));$c1->read();$c1b->read();$c2->read();$this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));$this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));}public function test_template_has_related_data(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$user = $dg->create_user();$lpg = $dg->get_plugin_generator('core_competency');$tpl1 = $lpg->create_template();$tpl2 = $lpg->create_template();// Create plans for first template.$time = time();$plan1 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $user->id,'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));$this->assertTrue(api::template_has_related_data($tpl1->get('id')));$this->assertFalse(api::template_has_related_data($tpl2->get('id')));}public function test_delete_template_delete_plans(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$u1 = $dg->create_user();$f = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$tpl = $lpg->create_template();$tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1->get('id'),'sortorder' => 1));$tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c2->get('id'),'sortorder' => 2));$p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));// Check pre-test.$this->assertTrue(\core_competency\template::record_exists($tpl->get('id')));$this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get('id')));$this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));$result = api::delete_template($tpl->get('id'), true);$this->assertTrue($result);// Check that the template does not exist anymore.$this->assertFalse(\core_competency\template::record_exists($tpl->get('id')));// Check that associated competencies are also deleted.$this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get('id')));// Check that associated plan are also deleted.$this->assertEquals(0, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));}public function test_delete_template_unlink_plans(): void {$this->resetAfterTest(true);$this->setAdminUser();$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$u1 = $dg->create_user();$f = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));$tpl = $lpg->create_template();$tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1->get('id'),'sortorder' => 1));$tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c2->get('id'),'sortorder' => 2));$p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));// Check pre-test.$this->assertTrue(\core_competency\template::record_exists($tpl->get('id')));$this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get('id')));$this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));$result = api::delete_template($tpl->get('id'), false);$this->assertTrue($result);// Check that the template does not exist anymore.$this->assertFalse(\core_competency\template::record_exists($tpl->get('id')));// Check that associated competencies are also deleted.$this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get('id')));// Check that associated plan still exist but unlink from template.$plans = \core_competency\plan::get_records(array('id' => $p1->get('id')));$this->assertEquals(1, count($plans));$this->assertEquals($plans[0]->get('origtemplateid'), $tpl->get('id'));$this->assertNull($plans[0]->get('templateid'));}public function test_delete_competency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Set rules on parent competency.$c1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);$c1->set('ruletype', 'core_competency\\competency_rule_all');$c1->update();// If we delete competeny, the related competencies relations and evidences should be deleted.// Create related competencies using one of c1a competency descendants.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$evidence = $lpg->create_evidence(array('usercompetencyid' => $uc2->get('id')));$this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));$uc2->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));// Check that on delete, we reset the rule on parent competency.$c1->read();$this->assertNull($c1->get('ruletype'));$this->assertNull($c1->get('ruletype'));$this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));// Check that descendants were also deleted.$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(api::list_related_competencies($c2->get('id'))));// Delete a simple competency.$this->assertTrue(api::delete_competency($c2->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));}public function test_delete_competency_used_in_plan(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$plan = $lpg->create_plan((object) array('userid' => $u1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Add competency to plan.$pc = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c11b->get('id')));// We can not delete a competency , if competency or competency children is associated to plan.$this->assertFalse(api::delete_competency($c1a->get('id')));// We can delete the competency if we remove the competency from the plan.$pc->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));}public function test_delete_competency_used_in_usercompetency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create user competency.$uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));// We can not delete a competency , if competency or competency children exist in user competency.$this->assertFalse(api::delete_competency($c1a->get('id')));// We can delete the competency if we remove the competency from user competency.$uc1->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));}public function test_delete_competency_used_in_usercompetencyplan(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$plan = $lpg->create_plan((object) array('userid' => $u1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create user competency plan.$uc2 = $lpg->create_user_competency_plan(array('userid' => $u1->id,'competencyid' => $c11b->get('id'),'planid' => $plan->get('id')));// We can not delete a competency , if competency or competency children exist in user competency plan.$this->assertFalse(api::delete_competency($c1a->get('id')));// We can delete the competency if we remove the competency from user competency plan.$uc2->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));}public function test_delete_competency_used_in_template(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$template = $lpg->create_template();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Add competency to a template.$tc = $lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $c11b->get('id')));// We can not delete a competency , if competency or competency children is linked to template.$this->assertFalse(api::delete_competency($c1a->get('id')));// We can delete the competency if we remove the competency from template.$tc->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));}public function test_delete_competency_used_in_course(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$cat1 = $dg->create_category();$course = $dg->create_course(array('category' => $cat1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Add competency to course.$cc = $lpg->create_course_competency(array('courseid' => $course->id,'competencyid' => $c11b->get('id')));// We can not delete a competency if the competency or competencies children is linked to a course.$this->assertFalse(api::delete_competency($c1a->get('id')));// We can delete the competency if we remove the competency from course.$cc->delete();$this->assertTrue(api::delete_competency($c1a->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));}public function test_delete_framework(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// If we delete framework, the related competencies relations and evidences should be deleted.// Create related competencies using one of c1a competency descendants.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$evidence = $lpg->create_evidence(array('usercompetencyid' => $uc2->get('id')));$this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));$uc2->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency_framework::record_exists($f1->get('id')));// Check that all competencies were also deleted.$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));// Delete a simple framework.$f2 = $lpg->create_framework();$this->assertTrue(api::delete_framework($f2->get('id')));$this->assertFalse(competency_framework::record_exists($f2->get('id')));}public function test_delete_framework_competency_used_in_plan(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$plan = $lpg->create_plan((object) array('userid' => $u1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create related competencies.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$usercompetencyid = $uc2->get('id');$evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));$this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));$uc2->delete();// Add competency to plan.$pc = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c11b->get('id')));// We can not delete a framework , if competency or competency children is associated to plan.$this->assertFalse(api::delete_framework($f1->get('id')));// Check that none of associated data are deleted.$this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));$this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));// We can delete the competency if we remove the competency from the plan.$pc->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));}public function test_delete_framework_competency_used_in_usercompetency(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create related competencies.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$usercompetencyid = $uc1->get('id');$evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));$this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));$uc1->delete();// Create user competency.$uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));// We can not delete a framework , if competency or competency children exist in user competency.$this->assertFalse(api::delete_framework($f1->get('id')));// Check that none of associated data are deleted.$this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));$this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));// We can delete the framework if we remove the competency from user competency.$uc2->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));}public function test_delete_framework_competency_used_in_usercompetencyplan(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$plan = $lpg->create_plan((object) array('userid' => $u1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create related competencies.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$usercompetencyid = $uc1->get('id');$evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));$this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));$uc1->delete();// Create user competency plan.$uc2 = $lpg->create_user_competency_plan(array('userid' => $u1->id,'competencyid' => $c11b->get('id'),'planid' => $plan->get('id')));// We can not delete a framework , if competency or competency children exist in user competency plan.$this->assertFalse(api::delete_framework($f1->get('id')));// Check that none of associated data are deleted.$this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));$this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));// We can delete the framework if we remove the competency from user competency plan.$uc2->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));}public function test_delete_framework_competency_used_in_template(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$template = $lpg->create_template();$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create related competencies.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$usercompetencyid = $uc1->get('id');$evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));$this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));$uc1->delete();// Add competency to a template.$tc = $lpg->create_template_competency(array('templateid' => $template->get('id'),'competencyid' => $c11b->get('id')));// We can not delete a framework , if competency or competency children is linked to template.$this->assertFalse(api::delete_framework($f1->get('id')));// Check that none of associated data are deleted.$this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));$this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));// We can delete the framework if we remove the competency from template.$tc->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));}public function test_delete_framework_competency_used_in_course(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$cat1 = $dg->create_category();$u1 = $dg->create_user();$course = $dg->create_course(array('category' => $cat1->id));$f1 = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));$c2id = $c2->get('id');$c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));$c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));$c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));$c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));// Create related competencies.$rc = $lpg->create_related_competency(array('competencyid' => $c2->get('id'),'relatedcompetencyid' => $c11b->get('id')));$this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));// Creating a standard evidence with minimal information.$uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));$usercompetencyid = $uc1->get('id');$evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));$this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));$uc1->delete();// Add competency to course.$cc = $lpg->create_course_competency(array('courseid' => $course->id,'competencyid' => $c11b->get('id')));// We can not delete a framework if the competency or competencies children is linked to a course.$this->assertFalse(api::delete_framework($f1->get('id')));// Check that none of associated data are deleted.$this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));$this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));// We can delete the framework if we remove the competency from course.$cc->delete();$this->assertTrue(api::delete_framework($f1->get('id')));$this->assertFalse(competency::record_exists($c1->get('id')));$this->assertFalse(competency::record_exists($c2->get('id')));$this->assertFalse(competency::record_exists($c1a->get('id')));$this->assertFalse(competency::record_exists($c1b->get('id')));$this->assertFalse(competency::record_exists($c11b->get('id')));$this->assertFalse(competency::record_exists($c12b->get('id')));// Check if evidence are also deleted.$this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));// Check if related conpetency relation is deleted.$this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));}public function test_grade_competency_in_course_permissions(): void {$this->resetAfterTest();$dg = $this->getDataGenerator();$c1 = $dg->create_course();$c2 = $dg->create_course();$sysctx = \context_system::instance();$c1ctx = \context_course::instance($c1->id);$c2ctx = \context_course::instance($c2->id);$teacher1 = $dg->create_user();$noneditingteacher = $dg->create_user();$student1 = $dg->create_user();$student2 = $dg->create_user();$notstudent1 = $dg->create_user();$lpg = $dg->get_plugin_generator('core_competency');$framework = $lpg->create_framework();$comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$lpg->create_course_competency(array('courseid' => $c1->id, 'competencyid' => $comp1->get('id')));$studentarch = get_archetype_roles('student');$studentrole = array_shift($studentarch);$gradablerole = $dg->create_role();assign_capability('moodle/competency:coursecompetencygradable', CAP_ALLOW, $gradablerole, $sysctx->id);$notgradablerole = $dg->create_role();assign_capability('moodle/competency:coursecompetencygradable', CAP_PROHIBIT, $notgradablerole, $sysctx->id);$canviewucrole = $dg->create_role();assign_capability('moodle/competency:usercompetencyview', CAP_ALLOW, $canviewucrole, $sysctx->id);$cannotviewcomp = $dg->create_role();assign_capability('moodle/competency:competencyview', CAP_PROHIBIT, $cannotviewcomp, $sysctx->id);$canmanagecomp = $dg->create_role();assign_capability('moodle/competency:competencymanage', CAP_ALLOW, $canmanagecomp, $sysctx->id);$cangraderole = $dg->create_role();assign_capability('moodle/competency:competencygrade', CAP_ALLOW, $cangraderole, $sysctx->id);// Enrol s1 and s2 as students in course 1.$dg->enrol_user($student1->id, $c1->id, $studentrole->id);$dg->enrol_user($student2->id, $c1->id, $studentrole->id);// Mark the s2 as not being 'gradable'.$dg->role_assign($notgradablerole, $student2->id, $c1ctx->id);// Mark the 'non a student' as 'gradable' throughout the site.$dg->role_assign($gradablerole, $notstudent1->id, $sysctx->id);// From now we'll iterate over each permission.accesslib_clear_all_caches_for_unit_testing();$this->setUser($teacher1);$this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'View a user competency',$c1->id, $student1->id, $comp1->get('id'));// Give permission to view competencies.$dg->role_assign($canviewucrole, $teacher1->id, $c1ctx->id);accesslib_clear_all_caches_for_unit_testing();$this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'Set competency rating',$c1->id, $student1->id, $comp1->get('id'));// Give permission to rate.$dg->role_assign($cangraderole, $teacher1->id, $c1ctx->id);accesslib_clear_all_caches_for_unit_testing();$this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));// Remove permssion to read competencies, this leads to error.$dg->role_assign($cannotviewcomp, $teacher1->id, $sysctx->id);accesslib_clear_all_caches_for_unit_testing();$this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'View competency frameworks',$c1->id, $student1->id, $comp1->get('id'));// Give permssion to manage course competencies, this leads to success.$dg->role_assign($canmanagecomp, $teacher1->id, $sysctx->id);accesslib_clear_all_caches_for_unit_testing();$this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));// Try to grade a user that is not gradable, lead to errors.$this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency may not be rated at this time.',$c1->id, $student2->id, $comp1->get('id'));// Try to grade a competency not in the course.$this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency does not belong to this course',$c1->id, $student1->id, $comp2->get('id'));// Try to grade a user that is not enrolled, even though they are 'gradable'.$this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency may not be rated at this time.',$c1->id, $notstudent1->id, $comp1->get('id'));// Give permission for non-editing teacher to grade.$dg->role_assign($canviewucrole, $noneditingteacher->id, $c1ctx->id);$dg->role_assign($cangraderole, $noneditingteacher->id, $c1ctx->id);$this->setUser($noneditingteacher);accesslib_clear_all_caches_for_unit_testing();$this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));}/*** Assert that a competency was graded in a course.** @param int $courseid The course ID.* @param int $userid The user ID.* @param int $compid The competency ID.* @param int $grade The grade.*/protected function assertSuccessWithGradeCompetencyInCourse($courseid, $userid, $compid, $grade = 1) {$beforecount = evidence::count_records();api::grade_competency_in_course($courseid, $userid, $compid, $grade);$this->assertEquals($beforecount + 1, evidence::count_records());$uc = user_competency::get_record(array('userid' => $userid, 'competencyid' => $compid));$records = evidence::get_records(array(), 'id', 'DESC', 0, 1);$evidence = array_pop($records);$this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));}/*** Assert that grading a competency in course throws an exception.** @param string $exceptiontype The exception type.* @param string $exceptiontest The exceptiont text.* @param int $courseid The course ID.* @param int $userid The user ID.* @param int $compid The competency ID.* @param int $grade The grade.*/protected function assertExceptionWithGradeCompetencyInCourse($exceptiontype, $exceptiontext, $courseid, $userid, $compid,$grade = 1) {$raised = false;try {api::grade_competency_in_course($courseid, $userid, $compid, $grade);} catch (\moodle_exception $e) {$raised = true;$this->assertInstanceOf($exceptiontype, $e);$this->assertMatchesRegularExpression('@' . $exceptiontext . '@', $e->getMessage());}if (!$raised) {$this->fail('Grading should not be allowed.');}}/*** Test list of evidences for plan completed and not completed.*/public function test_list_evidence(): void {global $DB;$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$syscontext = \context_system::instance();// Create users.$user = $dg->create_user();$this->setUser($user);// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create 2 user plans and add competency to each plan.$p1 = $lpg->create_plan(array('userid' => $user->id));$p2 = $lpg->create_plan(array('userid' => $user->id));$pc1 = $lpg->create_plan_competency(array('planid' => $p1->get('id'), 'competencyid' => $c1->get('id')));$pc2 = $lpg->create_plan_competency(array('planid' => $p2->get('id'), 'competencyid' => $c1->get('id')));// Create user competency and add an evidence.$uc = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));$e1 = $lpg->create_evidence(array('usercompetencyid' => $uc->get('id')));// Check both plans as one evidence.$this->assertEquals(1, count(api::list_evidence($user->id, $c1->get('id'), $p1->get('id'))));$this->assertEquals(1, count(api::list_evidence($user->id, $c1->get('id'), $p2->get('id'))));// Complete second plan.$p2->set('status', plan::STATUS_COMPLETE);$p2->update();// Add another evidence for the same competency, but in the future (time + 1).$e2 = $lpg->create_evidence(array('usercompetencyid' => $uc->get('id')));$evidencesql = "UPDATE {" . evidence::TABLE . "} SET timecreated = :currenttime WHERE id = :evidenceid";$DB->execute($evidencesql, array('currenttime' => time() + 1, 'evidenceid' => $e2->get('id')));// Check that the first plan, which is not completed, has all the evidence.$this->assertEquals(2, count(api::list_evidence($user->id, $c1->get('id'), $p1->get('id'))));// Check that the second plan, completed before the new evidence, only has the first piece of evidence.$listevidences = api::list_evidence($user->id, $c1->get('id'), $p2->get('id'));$this->assertEquals(1, count($listevidences));$this->assertEquals($e1->get('id'), $listevidences[$e1->get('id')]->get('id'));}/*** Get a user competency in a course.*/public function test_get_user_competency_in_course(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$user = $dg->create_user();$c1 = $dg->create_course();// Enrol the user so they can be rated in the course.$studentarch = get_archetype_roles('student');$studentrole = array_shift($studentarch);$coursecontext = \context_course::instance($c1->id);$dg->role_assign($studentrole->id, $user->id, $coursecontext->id);$dg->enrol_user($user->id, $c1->id, $studentrole->id);$framework = $lpg->create_framework();$comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));// Create a user competency for comp1.api::grade_competency_in_course($c1, $user->id, $comp1->get('id'), 3, 'Unit test');// Test for competency already exist in user_competency.$uc = api::get_user_competency_in_course($c1->id, $user->id, $comp1->get('id'));$this->assertEquals($comp1->get('id'), $uc->get('competencyid'));$this->assertEquals($user->id, $uc->get('userid'));$this->assertEquals(3, $uc->get('grade'));$this->assertEquals(true, $uc->get('proficiency'));// Test for competency does not exist in user_competency.$uc2 = api::get_user_competency_in_course($c1->id, $user->id, $comp2->get('id'));$this->assertEquals($comp2->get('id'), $uc2->get('competencyid'));$this->assertEquals($user->id, $uc2->get('userid'));$this->assertEquals(null, $uc2->get('grade'));$this->assertEquals(null, $uc2->get('proficiency'));}/*** Test course statistics api functions.*/public function test_course_statistics(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$u2 = $dg->create_user();$u3 = $dg->create_user();$u4 = $dg->create_user();$c1 = $dg->create_course();$framework = $lpg->create_framework();// Enrol students in the course.$studentarch = get_archetype_roles('student');$studentrole = array_shift($studentarch);$coursecontext = \context_course::instance($c1->id);$dg->role_assign($studentrole->id, $u1->id, $coursecontext->id);$dg->enrol_user($u1->id, $c1->id, $studentrole->id);$dg->role_assign($studentrole->id, $u2->id, $coursecontext->id);$dg->enrol_user($u2->id, $c1->id, $studentrole->id);$dg->role_assign($studentrole->id, $u3->id, $coursecontext->id);$dg->enrol_user($u3->id, $c1->id, $studentrole->id);$dg->role_assign($studentrole->id, $u4->id, $coursecontext->id);$dg->enrol_user($u4->id, $c1->id, $studentrole->id);// Create 6 competencies.$comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp5 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp6 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Link 6 out of 6 to a course.$lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp3->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp4->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp5->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp6->get('id'), 'courseid' => $c1->id));// Rate some competencies.// User 1.api::grade_competency_in_course($c1, $u1->id, $comp1->get('id'), 4, 'Unit test');api::grade_competency_in_course($c1, $u1->id, $comp2->get('id'), 4, 'Unit test');api::grade_competency_in_course($c1, $u1->id, $comp3->get('id'), 4, 'Unit test');api::grade_competency_in_course($c1, $u1->id, $comp4->get('id'), 4, 'Unit test');// User 2.api::grade_competency_in_course($c1, $u2->id, $comp1->get('id'), 1, 'Unit test');api::grade_competency_in_course($c1, $u2->id, $comp2->get('id'), 1, 'Unit test');api::grade_competency_in_course($c1, $u2->id, $comp3->get('id'), 1, 'Unit test');api::grade_competency_in_course($c1, $u2->id, $comp4->get('id'), 1, 'Unit test');// User 3.api::grade_competency_in_course($c1, $u3->id, $comp1->get('id'), 3, 'Unit test');api::grade_competency_in_course($c1, $u3->id, $comp2->get('id'), 3, 'Unit test');// User 4.api::grade_competency_in_course($c1, $u4->id, $comp1->get('id'), 2, 'Unit test');api::grade_competency_in_course($c1, $u4->id, $comp2->get('id'), 2, 'Unit test');// OK we have enough data - lets call some API functions and check for expected results.$result = api::count_proficient_competencies_in_course_for_user($c1->id, $u1->id);$this->assertEquals(4, $result);$result = api::count_proficient_competencies_in_course_for_user($c1->id, $u2->id);$this->assertEquals(0, $result);$result = api::count_proficient_competencies_in_course_for_user($c1->id, $u3->id);$this->assertEquals(2, $result);$result = api::count_proficient_competencies_in_course_for_user($c1->id, $u4->id);$this->assertEquals(0, $result);$result = api::get_least_proficient_competencies_for_course($c1->id, 0, 2);// We should get 5 and 6 in repeatable order.$valid = false;if (($comp5->get('id') == $result[0]->get('id')) || ($comp6->get('id') == $result[0]->get('id'))) {$valid = true;}$this->assertTrue($valid);$valid = false;if (($comp5->get('id') == $result[1]->get('id')) || ($comp6->get('id') == $result[1]->get('id'))) {$valid = true;}$this->assertTrue($valid);$expected = $result[1]->get('id');$result = api::get_least_proficient_competencies_for_course($c1->id, 1, 1);$this->assertEquals($result[0]->get('id'), $expected);}/*** Test template statistics api functions.*/public function test_template_statistics(): void {$this->resetAfterTest(true);$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$this->setAdminUser();$u1 = $dg->create_user();$u2 = $dg->create_user();$u3 = $dg->create_user();$u4 = $dg->create_user();$c1 = $dg->create_course();$framework = $lpg->create_framework();// Create 6 competencies.$comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp5 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));$comp6 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Link 5 out of 6 to a course.$lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp3->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp4->get('id'), 'courseid' => $c1->id));$lpg->create_course_competency(array('competencyid' => $comp5->get('id'), 'courseid' => $c1->id));// Put all 6 in a template.$tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();$tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp1->get('id')));$tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp2->get('id')));$tplc3 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp3->get('id')));$tplc4 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp4->get('id')));$tplc5 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp5->get('id')));$tplc6 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp6->get('id')));// Create some plans from the template.$p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));$p2 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u2->id));$p3 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u3->id));$p4 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u4->id));// Rate some competencies.// User 1.$lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp1->get('id'),'proficiency' => true, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp2->get('id'),'proficiency' => true, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp3->get('id'),'proficiency' => true, 'grade' => 1 ));// User 2.$lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp1->get('id'),'proficiency' => false, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp2->get('id'),'proficiency' => false, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp3->get('id'),'proficiency' => false, 'grade' => 1 ));// User 3.$lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp2->get('id'),'proficiency' => false, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp3->get('id'),'proficiency' => true, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp4->get('id'),'proficiency' => false, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp5->get('id'),'proficiency' => true, 'grade' => 1 ));// User 4.$lpg->create_user_competency(array('userid' => $u4->id, 'competencyid' => $comp3->get('id'),'proficiency' => true, 'grade' => 1 ));$lpg->create_user_competency(array('userid' => $u4->id, 'competencyid' => $comp5->get('id'),'proficiency' => true, 'grade' => 1 ));// Complete 3 out of 4 plans.api::complete_plan($p1->get('id'));api::complete_plan($p2->get('id'));api::complete_plan($p3->get('id'));// OK we have enough data - lets call some API functions and check for expected results.$result = api::count_competencies_in_template_with_no_courses($tpl->get('id'));$this->assertEquals(1, $result);$result = api::count_plans_for_template($tpl->get('id'));$this->assertEquals(4, $result);$result = api::count_plans_for_template($tpl->get('id'), plan::STATUS_COMPLETE);$this->assertEquals(3, $result);// This counts the records of competencies in completed plans for all users with a plan from this template.$result = api::count_user_competency_plans_for_template($tpl->get('id'));// There should be 3 plans * 6 competencies.$this->assertEquals(18, $result);// This counts the records of proficient competencies in completed plans for all users with a plan from this template.$result = api::count_user_competency_plans_for_template($tpl->get('id'), true);// There should be 5.$this->assertEquals(5, $result);// This counts the records of not proficient competencies in completed plans for all users with a plan from this template.$result = api::count_user_competency_plans_for_template($tpl->get('id'), false);// There should be 13.$this->assertEquals(13, $result);// This lists the plans based on this template, optionally filtered by status.$result = api::list_plans_for_template($tpl->get('id'));$this->assertEquals(4, count($result));foreach ($result as $one) {$this->assertInstanceOf('\core_competency\plan', $one);}// This lists the plans based on this template, optionally filtered by status.$result = api::list_plans_for_template($tpl->get('id'), plan::STATUS_COMPLETE);$this->assertEquals(3, count($result));foreach ($result as $one) {$this->assertInstanceOf('\core_competency\plan', $one);$this->assertEquals(plan::STATUS_COMPLETE, $one->get('status'));}$result = api::get_least_proficient_competencies_for_template($tpl->get('id'), 0, 2);// Our times completed counts should look like this:// - comp1 - 1// - comp2 - 1// - comp3 - 2// - comp4 - 0// - comp5 - 1// - comp6 - 0//// And this is a fullstop to make CiBoT happy.$this->assertEquals(2, count($result));$leastarray = array($comp4->get('id'), $comp6->get('id'));foreach ($result as $one) {$this->assertInstanceOf('\core_competency\competency', $one);$this->assertContainsEquals($one->get('id'), $leastarray);}}public function test_is_scale_used_anywhere(): void {$this->resetAfterTest();$dg = $this->getDataGenerator();$lpg = $dg->get_plugin_generator('core_competency');$scale1 = $dg->create_scale();$scale2 = $dg->create_scale();$scale3 = $dg->create_scale();$scale4 = $dg->create_scale();$this->assertFalse(api::is_scale_used_anywhere($scale1->id));$this->assertFalse(api::is_scale_used_anywhere($scale2->id));$this->assertFalse(api::is_scale_used_anywhere($scale3->id));$this->assertFalse(api::is_scale_used_anywhere($scale4->id));// Using scale 1 in a framework.$f1 = $lpg->create_framework(['scaleid' => $scale1->id,'scaleconfiguration' => json_encode([['scaleid' => $scale1->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$this->assertTrue(api::is_scale_used_anywhere($scale1->id));$this->assertFalse(api::is_scale_used_anywhere($scale2->id));$this->assertFalse(api::is_scale_used_anywhere($scale3->id));$this->assertFalse(api::is_scale_used_anywhere($scale4->id));// Using scale 2 in a competency.$f2 = $lpg->create_framework();$c2 = $lpg->create_competency(['competencyframeworkid' => $f2->get('id'),'scaleid' => $scale2->id,'scaleconfiguration' => json_encode([['scaleid' => $scale2->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$this->assertTrue(api::is_scale_used_anywhere($scale1->id));$this->assertTrue(api::is_scale_used_anywhere($scale2->id));$this->assertFalse(api::is_scale_used_anywhere($scale3->id));$this->assertFalse(api::is_scale_used_anywhere($scale4->id));// Using scale 3 in a framework, and scale 4 in a competency of that framework.$f3 = $lpg->create_framework(['scaleid' => $scale3->id,'scaleconfiguration' => json_encode([['scaleid' => $scale3->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$c3 = $lpg->create_competency(['competencyframeworkid' => $f3->get('id'),'scaleid' => $scale4->id,'scaleconfiguration' => json_encode([['scaleid' => $scale4->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$this->assertTrue(api::is_scale_used_anywhere($scale1->id));$this->assertTrue(api::is_scale_used_anywhere($scale2->id));$this->assertTrue(api::is_scale_used_anywhere($scale3->id));$this->assertTrue(api::is_scale_used_anywhere($scale4->id));// Multiple occurrences of the same scale (3, and 4).$f4 = $lpg->create_framework(['scaleid' => $scale3->id,'scaleconfiguration' => json_encode([['scaleid' => $scale3->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$c4 = $lpg->create_competency(['competencyframeworkid' => $f3->get('id'),'scaleid' => $scale4->id,'scaleconfiguration' => json_encode([['scaleid' => $scale4->id],['id' => 1, 'scaledefault' => 1, 'proficient' => 1]])]);$this->assertTrue(api::is_scale_used_anywhere($scale1->id));$this->assertTrue(api::is_scale_used_anywhere($scale2->id));$this->assertTrue(api::is_scale_used_anywhere($scale3->id));$this->assertTrue(api::is_scale_used_anywhere($scale4->id));}public function test_delete_evidence(): void {$this->resetAfterTest();$dg = $this->getDataGenerator();$ccg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$f1 = $ccg->create_framework();$comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$uc1 = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]);$ev1 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);$ev2 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);$this->setAdminUser($u1);$this->assertEquals(2, evidence::count_records());api::delete_evidence($ev1);$this->assertEquals(1, evidence::count_records());$this->assertFalse(evidence::record_exists($ev1->get('id')));$this->assertTrue(evidence::record_exists($ev2->get('id')));}public function test_delete_evidence_without_permissions(): void {$this->resetAfterTest();$dg = $this->getDataGenerator();$ccg = $dg->get_plugin_generator('core_competency');$u1 = $dg->create_user();$f1 = $ccg->create_framework();$comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$uc1 = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]);$ev1 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);$this->setUser($u1);$this->expectException(\required_capability_exception::class);api::delete_evidence($ev1);}public function test_list_plans_to_review(): void {$dg = $this->getDataGenerator();$this->resetAfterTest();$ccg = $dg->get_plugin_generator('core_competency');$sysctx = \context_system::instance();$this->setAdminUser();$reviewer = $dg->create_user();$roleallow = $dg->create_role();$roleprohibit = $dg->create_role();assign_capability('moodle/competency:planreview', CAP_ALLOW, $roleallow, $sysctx->id);assign_capability('moodle/competency:planreview', CAP_PROHIBIT, $roleprohibit, $sysctx->id);role_assign($roleallow, $reviewer->id, $sysctx->id);accesslib_clear_all_caches_for_unit_testing();$u1 = $dg->create_user();$u2 = $dg->create_user();$f1 = $ccg->create_framework();$comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$p1a = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_WAITING_FOR_REVIEW]);$p1b = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_IN_REVIEW, 'reviewerid' => $reviewer->id]);$p1c = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_DRAFT]);$p2a = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_WAITING_FOR_REVIEW]);$p2b = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_IN_REVIEW]);$p2c = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_ACTIVE]);$p2d = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_ACTIVE]);api::complete_plan($p2d);// The reviewer can review all plans waiting for review, or in review where they are the reviewer.$this->setUser($reviewer);$result = api::list_plans_to_review();$this->assertEquals(3, $result['count']);$this->assertEquals($p1a->get('id'), $result['plans'][0]->plan->get('id'));$this->assertEquals($p1b->get('id'), $result['plans'][1]->plan->get('id'));$this->assertEquals($p2a->get('id'), $result['plans'][2]->plan->get('id'));// The reviewer cannot view the plans when they do not have the permission in the user's context.role_assign($roleprohibit, $reviewer->id, \context_user::instance($u2->id)->id);accesslib_clear_all_caches_for_unit_testing();$result = api::list_plans_to_review();$this->assertEquals(2, $result['count']);$this->assertEquals($p1a->get('id'), $result['plans'][0]->plan->get('id'));$this->assertEquals($p1b->get('id'), $result['plans'][1]->plan->get('id'));}public function test_list_user_competencies_to_review(): void {global $CFG;require_once($CFG->dirroot . '/user/lib.php');$dg = $this->getDataGenerator();$this->resetAfterTest();$ccg = $dg->get_plugin_generator('core_competency');$sysctx = \context_system::instance();$this->setAdminUser();$reviewer = $dg->create_user();$roleallow = $dg->create_role();$roleprohibit = $dg->create_role();assign_capability('moodle/competency:usercompetencyreview', CAP_ALLOW, $roleallow, $sysctx->id);assign_capability('moodle/competency:usercompetencyreview', CAP_PROHIBIT, $roleprohibit, $sysctx->id);role_assign($roleallow, $reviewer->id, $sysctx->id);accesslib_clear_all_caches_for_unit_testing();$u1 = $dg->create_user();$u2 = $dg->create_user();$u3 = $dg->create_user();$f1 = $ccg->create_framework();$c1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$c2 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$c3 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$c4 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);$uc1a = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c1->get('id'),'status' => user_competency::STATUS_IDLE]);$uc1b = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c2->get('id'),'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);$uc1c = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c3->get('id'),'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $reviewer->id]);$uc2a = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c1->get('id'),'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);$uc2b = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c2->get('id'),'status' => user_competency::STATUS_IDLE]);$uc2c = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c3->get('id'),'status' => user_competency::STATUS_IN_REVIEW]);$uc3a = $ccg->create_user_competency(['userid' => $u3->id, 'competencyid' => $c4->get('id'),'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);// The reviewer can review all plans waiting for review, or in review where they are the reviewer.$this->setUser($reviewer);$result = api::list_user_competencies_to_review();$this->assertEquals(4, $result['count']);$this->assertEquals($uc2a->get('id'), $result['competencies'][0]->usercompetency->get('id'));$this->assertEquals($uc1b->get('id'), $result['competencies'][1]->usercompetency->get('id'));$this->assertEquals($uc1c->get('id'), $result['competencies'][2]->usercompetency->get('id'));$this->assertEquals($uc3a->get('id'), $result['competencies'][3]->usercompetency->get('id'));// Now, let's delete user 3.// It should not be listed on user competencies to review any more.user_delete_user($u3);$result = api::list_user_competencies_to_review();$this->assertEquals(3, $result['count']);// The reviewer cannot view the plans when they do not have the permission in the user's context.role_assign($roleprohibit, $reviewer->id, \context_user::instance($u2->id)->id);accesslib_clear_all_caches_for_unit_testing();$result = api::list_user_competencies_to_review();$this->assertEquals(2, $result['count']);$this->assertEquals($uc1b->get('id'), $result['competencies'][0]->usercompetency->get('id'));$this->assertEquals($uc1c->get('id'), $result['competencies'][1]->usercompetency->get('id'));}/*** Test we can get all of a users plans with a competency.*/public function test_list_plans_with_competency(): void {$this->resetAfterTest(true);$this->setAdminUser();$lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');$u1 = $this->getDataGenerator()->create_user();$tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();// Create a framework and assign competencies.$framework = $lpg->create_framework();$c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));// Create two plans and assign the competency to each.$plan1 = $lpg->create_plan(array('userid' => $u1->id));$plan2 = $lpg->create_plan(array('userid' => $u1->id));$lpg->create_plan_competency(array('planid' => $plan1->get('id'), 'competencyid' => $c1->get('id')));$lpg->create_plan_competency(array('planid' => $plan2->get('id'), 'competencyid' => $c1->get('id')));// Create one more plan without the competency.$plan3 = $lpg->create_plan(array('userid' => $u1->id));$plans = api::list_plans_with_competency($u1->id, $c1);$this->assertEquals(2, count($plans));$this->assertEquals(reset($plans)->get('id'), $plan1->get('id'));$this->assertEquals(end($plans)->get('id'), $plan2->get('id'));}}