Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * API tests.
  19   *
  20   * @package    core_competency
  21   * @copyright  2015 Frédéric Massart - FMCorz.net
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  global $CFG;
  27  
  28  use core_competency\api;
  29  use core_competency\competency;
  30  use core_competency\competency_framework;
  31  use core_competency\course_competency_settings;
  32  use core_competency\evidence;
  33  use core_competency\user_competency;
  34  use core_competency\plan;
  35  
  36  /**
  37   * API tests.
  38   *
  39   * @package    core_competency
  40   * @copyright  2015 Frédéric Massart - FMCorz.net
  41   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  42   */
  43  class core_competency_api_testcase extends advanced_testcase {
  44  
  45      public function test_get_framework_related_contexts() {
  46          $this->resetAfterTest(true);
  47          $dg = $this->getDataGenerator();
  48          $cat1 = $dg->create_category();
  49          $cat2 = $dg->create_category(array('parent' => $cat1->id));
  50          $cat3 = $dg->create_category(array('parent' => $cat2->id));
  51          $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
  52  
  53          $cat1ctx = context_coursecat::instance($cat1->id);
  54          $cat2ctx = context_coursecat::instance($cat2->id);
  55          $cat3ctx = context_coursecat::instance($cat3->id);
  56          $sysctx = context_system::instance();
  57  
  58          $expected = array($cat1ctx->id => $cat1ctx);
  59          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));
  60  
  61          $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);
  62          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));
  63  
  64          $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);
  65          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));
  66      }
  67  
  68      public function test_get_framework_related_contexts_with_capabilities() {
  69          $this->resetAfterTest(true);
  70          $dg = $this->getDataGenerator();
  71          $user = $dg->create_user();
  72          $cat1 = $dg->create_category();
  73          $cat2 = $dg->create_category(array('parent' => $cat1->id));
  74          $cat3 = $dg->create_category(array('parent' => $cat2->id));
  75          $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
  76  
  77          $cat1ctx = context_coursecat::instance($cat1->id);
  78          $cat2ctx = context_coursecat::instance($cat2->id);
  79          $cat3ctx = context_coursecat::instance($cat3->id);
  80          $sysctx = context_system::instance();
  81  
  82          $roleallow = create_role('Allow', 'allow', 'Allow read');
  83          assign_capability('moodle/competency:competencyview', CAP_ALLOW, $roleallow, $sysctx->id);
  84          role_assign($roleallow, $user->id, $sysctx->id);
  85  
  86          $roleprevent = create_role('Prevent', 'prevent', 'Prevent read');
  87          assign_capability('moodle/competency:competencyview', CAP_PROHIBIT, $roleprevent, $sysctx->id);
  88          role_assign($roleprevent, $user->id, $cat2ctx->id);
  89  
  90          accesslib_clear_all_caches_for_unit_testing();
  91          $this->setUser($user);
  92          $this->assertFalse(has_capability('moodle/competency:competencyview', $cat2ctx));
  93  
  94          $requiredcap = array('moodle/competency:competencyview');
  95  
  96          $expected = array();
  97          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));
  98  
  99          $expected = array($cat1ctx->id => $cat1ctx);
 100          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));
 101  
 102          $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);
 103          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));
 104      }
 105  
 106      public function test_get_template_related_contexts() {
 107          $this->resetAfterTest(true);
 108          $dg = $this->getDataGenerator();
 109          $cat1 = $dg->create_category();
 110          $cat2 = $dg->create_category(array('parent' => $cat1->id));
 111          $cat3 = $dg->create_category(array('parent' => $cat2->id));
 112          $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
 113  
 114          $cat1ctx = context_coursecat::instance($cat1->id);
 115          $cat2ctx = context_coursecat::instance($cat2->id);
 116          $cat3ctx = context_coursecat::instance($cat3->id);
 117          $sysctx = context_system::instance();
 118  
 119          $expected = array($cat1ctx->id => $cat1ctx);
 120          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self'));
 121  
 122          $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx);
 123          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children'));
 124  
 125          $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx);
 126          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents'));
 127      }
 128  
 129      public function test_get_template_related_contexts_with_capabilities() {
 130          $this->resetAfterTest(true);
 131          $dg = $this->getDataGenerator();
 132          $user = $dg->create_user();
 133          $cat1 = $dg->create_category();
 134          $cat2 = $dg->create_category(array('parent' => $cat1->id));
 135          $cat3 = $dg->create_category(array('parent' => $cat2->id));
 136          $c1 = $dg->create_course(array('category' => $cat2->id));   // This context should not be returned.
 137  
 138          $cat1ctx = context_coursecat::instance($cat1->id);
 139          $cat2ctx = context_coursecat::instance($cat2->id);
 140          $cat3ctx = context_coursecat::instance($cat3->id);
 141          $sysctx = context_system::instance();
 142  
 143          $roleallow = create_role('Allow', 'allow', 'Allow read');
 144          assign_capability('moodle/competency:templateview', CAP_ALLOW, $roleallow, $sysctx->id);
 145          role_assign($roleallow, $user->id, $sysctx->id);
 146  
 147          $roleprevent = create_role('Prevent', 'prevent', 'Prevent read');
 148          assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $roleprevent, $sysctx->id);
 149          role_assign($roleprevent, $user->id, $cat2ctx->id);
 150  
 151          accesslib_clear_all_caches_for_unit_testing();
 152          $this->setUser($user);
 153          $this->assertFalse(has_capability('moodle/competency:templateview', $cat2ctx));
 154  
 155          $requiredcap = array('moodle/competency:templateview');
 156  
 157          $expected = array();
 158          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap));
 159  
 160          $expected = array($cat1ctx->id => $cat1ctx);
 161          $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap));
 162  
 163          $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx);
 164          $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap));
 165      }
 166  
 167      /**
 168       * Test updating a template.
 169       */
 170      public function test_update_template() {
 171          $cat = $this->getDataGenerator()->create_category();
 172          $this->resetAfterTest(true);
 173          $this->setAdminUser();
 174  
 175          $syscontext = context_system::instance();
 176          $template = api::create_template((object) array('shortname' => 'testing', 'contextid' => $syscontext->id));
 177  
 178          $this->assertEquals('testing', $template->get('shortname'));
 179          $this->assertEquals($syscontext->id, $template->get('contextid'));
 180  
 181          // Simple update.
 182          api::update_template((object) array('id' => $template->get('id'), 'shortname' => 'success'));
 183          $template = api::read_template($template->get('id'));
 184          $this->assertEquals('success', $template->get('shortname'));
 185  
 186          // Trying to change the context.
 187          $this->expectException(coding_exception::class);
 188          api::update_template((object) array('id' => $template->get('id'), 'contextid' => context_coursecat::instance($cat->id)));
 189      }
 190  
 191      /**
 192       * Test listing framework with order param.
 193       */
 194      public function test_list_frameworks() {
 195          $this->resetAfterTest(true);
 196          $this->setAdminUser();
 197          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
 198  
 199          // Create a list of frameworks.
 200          $framework1 = $lpg->create_framework(array(
 201              'shortname' => 'shortname_alpha',
 202              'idnumber' => 'idnumber_cinnamon',
 203              'description' => 'description',
 204              'descriptionformat' => FORMAT_HTML,
 205              'visible' => true,
 206              'contextid' => context_system::instance()->id
 207          ));
 208  
 209          $framework2 = $lpg->create_framework(array(
 210              'shortname' => 'shortname_beetroot',
 211              'idnumber' => 'idnumber_apple',
 212              'description' => 'description',
 213              'descriptionformat' => FORMAT_HTML,
 214              'visible' => true,
 215              'contextid' => context_system::instance()->id
 216          ));
 217  
 218          $framework3 = $lpg->create_framework(array(
 219              'shortname' => 'shortname_crisps',
 220              'idnumber' => 'idnumber_beer',
 221              'description' => 'description',
 222              'descriptionformat' => FORMAT_HTML,
 223              'visible' => false,
 224              'contextid' => context_system::instance()->id
 225          ));
 226  
 227          // Get frameworks list order by shortname desc.
 228          $result = api::list_frameworks('shortname', 'DESC', null, 3, context_system::instance());
 229  
 230          $f = (object) array_shift($result);
 231          $this->assertEquals($framework3->get('id'), $f->get('id'));
 232          $f = (object) array_shift($result);
 233          $this->assertEquals($framework2->get('id'), $f->get('id'));
 234          $f = (object) array_shift($result);
 235          $this->assertEquals($framework1->get('id'), $f->get('id'));
 236  
 237          // Get frameworks list order by idnumber asc.
 238          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance());
 239  
 240          $f = (object) array_shift($result);
 241          $this->assertEquals($framework2->get('id'), $f->get('id'));
 242          $f = (object) array_shift($result);
 243          $this->assertEquals($framework3->get('id'), $f->get('id'));
 244          $f = (object) array_shift($result);
 245          $this->assertEquals($framework1->get('id'), $f->get('id'));
 246  
 247          // Repeat excluding the non-visible ones.
 248          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', true);
 249          $this->assertCount(2, $result);
 250          $f = (object) array_shift($result);
 251          $this->assertEquals($framework2->get('id'), $f->get('id'));
 252          $f = (object) array_shift($result);
 253          $this->assertEquals($framework1->get('id'), $f->get('id'));
 254  
 255          // Search by query string, trying match on shortname.
 256          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'crisp');
 257          $this->assertCount(1, $result);
 258          $f = (object) array_shift($result);
 259          $this->assertEquals($framework3->get('id'), $f->get('id'));
 260  
 261          // Search by query string, trying match on shortname, but hidden.
 262          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', true, 'crisp');
 263          $this->assertCount(0, $result);
 264  
 265          // Search by query string, trying match on ID number.
 266          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'apple');
 267          $this->assertCount(1, $result);
 268          $f = (object) array_shift($result);
 269          $this->assertEquals($framework2->get('id'), $f->get('id'));
 270  
 271          // Search by query string, trying match on both.
 272          $result = api::list_frameworks('idnumber', 'ASC', null, 3, context_system::instance(), 'self', false, 'bee');
 273          $this->assertCount(2, $result);
 274          $f = (object) array_shift($result);
 275          $this->assertEquals($framework2->get('id'), $f->get('id'));
 276          $f = (object) array_shift($result);
 277          $this->assertEquals($framework3->get('id'), $f->get('id'));
 278      }
 279  
 280      /**
 281       * Test duplicate a framework.
 282       */
 283      public function test_duplicate_framework() {
 284          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
 285          $this->resetAfterTest(true);
 286          $this->setAdminUser();
 287  
 288          $syscontext = context_system::instance();
 289          $params = array(
 290                  'shortname' => 'shortname_a',
 291                  'idnumber' => 'idnumber_c',
 292                  'description' => 'description',
 293                  'descriptionformat' => FORMAT_HTML,
 294                  'visible' => true,
 295                  'contextid' => $syscontext->id
 296          );
 297          $framework = $lpg->create_framework($params);
 298          $competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 299          $competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 300          $competency3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 301          $competency4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 302          $competency41 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),
 303                                                          'parentid' => $competency4->get('id'))
 304                                                      );
 305          $competency42 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),
 306                                                          'parentid' => $competency4->get('id'))
 307                                                      );
 308          $competencyidnumbers = array($competency1->get('idnumber'),
 309                                          $competency2->get('idnumber'),
 310                                          $competency3->get('idnumber'),
 311                                          $competency4->get('idnumber'),
 312                                          $competency41->get('idnumber'),
 313                                          $competency42->get('idnumber')
 314                                      );
 315  
 316          $config = json_encode(array(
 317              'base' => array('points' => 4),
 318              'competencies' => array(
 319                  array('id' => $competency41->get('id'), 'points' => 3, 'required' => 0),
 320                  array('id' => $competency42->get('id'), 'points' => 2, 'required' => 1),
 321              )
 322          ));
 323          $competency4->set('ruletype', 'core_competency\competency_rule_points');
 324          $competency4->set('ruleoutcome', \core_competency\competency::OUTCOME_EVIDENCE);
 325          $competency4->set('ruleconfig', $config);
 326          $competency4->update();
 327  
 328          api::add_related_competency($competency1->get('id'), $competency2->get('id'));
 329          api::add_related_competency($competency3->get('id'), $competency4->get('id'));
 330  
 331          $frameworkduplicated1 = api::duplicate_framework($framework->get('id'));
 332          $frameworkduplicated2 = api::duplicate_framework($framework->get('id'));
 333  
 334          $this->assertEquals($framework->get('idnumber').'_1', $frameworkduplicated1->get('idnumber'));
 335          $this->assertEquals($framework->get('idnumber').'_2', $frameworkduplicated2->get('idnumber'));
 336  
 337          $competenciesfr1 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated1->get('id')));
 338          $competenciesfr2 = api::list_competencies(array('competencyframeworkid' => $frameworkduplicated2->get('id')));
 339  
 340          $competencyidsfr1 = array();
 341          $competencyidsfr2 = array();
 342  
 343          foreach ($competenciesfr1 as $cmp) {
 344              $competencyidsfr1[] = $cmp->get('idnumber');
 345          }
 346          foreach ($competenciesfr2 as $cmp) {
 347              $competencyidsfr2[] = $cmp->get('idnumber');
 348          }
 349  
 350          $this->assertEmpty(array_diff($competencyidsfr1, $competencyidnumbers));
 351          $this->assertEmpty(array_diff($competencyidsfr2, $competencyidnumbers));
 352          $this->assertCount(6, $competenciesfr1);
 353          $this->assertCount(6, $competenciesfr2);
 354  
 355          // Test the related competencies.
 356          reset($competenciesfr1);
 357          $compduplicated1 = current($competenciesfr1);
 358          $relatedcompetencies = $compduplicated1->get_related_competencies();
 359          $comprelated = current($relatedcompetencies);
 360          $this->assertEquals($comprelated->get('idnumber'), $competency2->get('idnumber'));
 361  
 362          // Check if config rule have been ported correctly.
 363          $competency4duplicated = competency::get_record(array(
 364                                                              'idnumber' => $competency4->get('idnumber'),
 365                                                              'competencyframeworkid' => $frameworkduplicated2->get('id')
 366                                                          ));
 367          $configduplicated = json_decode($competency4duplicated->get('ruleconfig'), true);
 368          $configorigin = json_decode($config, true);
 369          // Check that the 2 config have the same base.
 370          $this->assertEquals($configorigin['base'], $configduplicated['base']);
 371          $this->assertEquals(count($configorigin['competencies']), count($configduplicated['competencies']));
 372          $competencyidsrules = array();
 373          foreach ($configduplicated['competencies'] as $key => $value) {
 374              // Check that the only difference between the 2 config is id competency.
 375              $this->assertEquals(1, count(array_diff($value, $configorigin['competencies'][$key])));
 376              $competencyidsrules[] = $value['id'];
 377          }
 378          $this->assertTrue($competency4duplicated->is_parent_of($competencyidsrules));
 379  
 380          // Test duplicate an empty framework.
 381          $emptyfrm = $lpg->create_framework();
 382          $emptyfrmduplicated = api::duplicate_framework($emptyfrm->get('id'));
 383          $this->assertEquals($emptyfrm->get('idnumber').'_1', $emptyfrmduplicated->get('idnumber'));
 384          $nbcomp = api::count_competencies(array('competencyframeworkid' => $emptyfrmduplicated->get('id')));
 385          $this->assertEquals(0, $nbcomp);
 386  
 387      }
 388  
 389      /**
 390       * Test update plan.
 391       */
 392      public function test_update_plan() {
 393          $this->resetAfterTest(true);
 394          $dg = $this->getDataGenerator();
 395          $usermanageowndraft = $dg->create_user();
 396          $usermanageown = $dg->create_user();
 397          $usermanagedraft = $dg->create_user();
 398          $usermanage = $dg->create_user();
 399  
 400          $syscontext = context_system::instance();
 401  
 402          // Creating specific roles.
 403          $manageowndraftrole = $dg->create_role(array(
 404              'name' => 'User manage own draft',
 405              'shortname' => 'manage-own-draft'
 406          ));
 407          $manageownrole = $dg->create_role(array(
 408              'name' => 'User manage own',
 409              'shortname' => 'manage-own'
 410          ));
 411          $managedraftrole = $dg->create_role(array(
 412              'name' => 'User manage draft',
 413              'shortname' => 'manage-draft'
 414          ));
 415          $managerole = $dg->create_role(array(
 416              'name' => 'User manage',
 417              'shortname' => 'manage'
 418          ));
 419  
 420          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);
 421          assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageowndraftrole, $syscontext->id);
 422  
 423          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);
 424          assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);
 425  
 426          assign_capability('moodle/competency:planmanagedraft', CAP_ALLOW, $managedraftrole, $syscontext->id);
 427          assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $managedraftrole, $syscontext->id);
 428  
 429          assign_capability('moodle/competency:planmanage', CAP_ALLOW, $managerole, $syscontext->id);
 430          assign_capability('moodle/competency:planview', CAP_ALLOW, $managerole, $syscontext->id);
 431  
 432          $dg->role_assign($manageowndraftrole, $usermanageowndraft->id, $syscontext->id);
 433          $dg->role_assign($manageownrole, $usermanageown->id, $syscontext->id);
 434          $dg->role_assign($managedraftrole, $usermanagedraft->id, $syscontext->id);
 435          $dg->role_assign($managerole, $usermanage->id, $syscontext->id);
 436  
 437          // Create first learning plan with user create draft.
 438          $this->setUser($usermanageowndraft);
 439          $plan = array (
 440              'name' => 'plan own draft',
 441              'description' => 'plan own draft',
 442              'userid' => $usermanageowndraft->id
 443          );
 444          $plan = api::create_plan((object)$plan);
 445          $record = $plan->to_record();
 446          $record->name = 'plan own draft modified';
 447  
 448          // Check if user create draft can edit the plan name.
 449          $plan = api::update_plan($record);
 450          $this->assertInstanceOf('\core_competency\plan', $plan);
 451  
 452          // The status cannot be changed in this method.
 453          $record->status = \core_competency\plan::STATUS_ACTIVE;
 454          try {
 455              $plan = api::update_plan($record);
 456              $this->fail('Updating the status is not allowed.');
 457          } catch (coding_exception $e) {
 458              $this->assertRegExp('/To change the status of a plan use the appropriate methods./', $e->getMessage());
 459          }
 460  
 461          // Test when user with manage own plan capability try to edit other user plan.
 462          $record->status = \core_competency\plan::STATUS_DRAFT;
 463          $record->name = 'plan create draft modified 2';
 464          $this->setUser($usermanageown);
 465          try {
 466              $plan = api::update_plan($record);
 467              $this->fail('User with manage own plan capability can only edit his own plan.');
 468          } catch (required_capability_exception $e) {
 469              $this->assertTrue(true);
 470          }
 471  
 472          // User with manage plan capability cannot edit the other user plans with status draft.
 473          $this->setUser($usermanage);
 474          $record->name = 'plan create draft modified 3';
 475          try {
 476              $plan = api::update_plan($record);
 477              $this->fail('User with manage plan capability cannot edit the other user plans with status draft');
 478          } catch (required_capability_exception $e) {
 479              $this->assertTrue(true);
 480          }
 481  
 482          // User with manage draft capability can edit other user's learning plan if the status is draft.
 483          $this->setUser($usermanagedraft);
 484          $record->status = \core_competency\plan::STATUS_DRAFT;
 485          $record->name = 'plan manage draft modified 3';
 486          $plan = api::update_plan($record);
 487          $this->assertInstanceOf('\core_competency\plan', $plan);
 488  
 489          // User with manage  plan capability can create/edit learning plan if status is active/complete.
 490          $this->setUser($usermanage);
 491          $plan = array (
 492              'name' => 'plan create',
 493              'description' => 'plan create',
 494              'userid' => $usermanage->id,
 495              'status' => \core_competency\plan::STATUS_ACTIVE
 496          );
 497          $plan = api::create_plan((object)$plan);
 498  
 499          // Silently transition to complete status to avoid errors about transitioning to complete.
 500          $plan->set('status', \core_competency\plan::STATUS_COMPLETE);
 501          $plan->update();
 502  
 503          $record = $plan->to_record();
 504          $record->name = 'plan create own modified';
 505          try {
 506              api::update_plan($record);
 507              $this->fail('Completed plan can not be edited');
 508          } catch (coding_exception $e) {
 509              $this->assertTrue(true);
 510          }
 511      }
 512  
 513      public function test_create_plan_from_template() {
 514          $this->resetAfterTest(true);
 515          $this->setAdminUser();
 516  
 517          $u1 = $this->getDataGenerator()->create_user();
 518          $tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();
 519  
 520          // Creating a new plan.
 521          $plan = api::create_plan_from_template($tpl, $u1->id);
 522          $record = $plan->to_record();
 523          $this->assertInstanceOf('\core_competency\plan', $plan);
 524          $this->assertTrue(\core_competency\plan::record_exists($plan->get('id')));
 525          $this->assertEquals($tpl->get('id'), $plan->get('templateid'));
 526          $this->assertEquals($u1->id, $plan->get('userid'));
 527          $this->assertTrue($plan->is_based_on_template());
 528  
 529          // Creating a plan that already exists.
 530          $plan = api::create_plan_from_template($tpl, $u1->id);
 531          $this->assertFalse($plan);
 532  
 533          // Check that api::create_plan cannot be used.
 534          unset($record->id);
 535          $this->expectException(coding_exception::class);
 536          $plan = api::create_plan($record);
 537      }
 538  
 539      public function test_update_plan_based_on_template() {
 540          $this->resetAfterTest(true);
 541          $dg = $this->getDataGenerator();
 542          $lpg = $dg->get_plugin_generator('core_competency');
 543          $u1 = $dg->create_user();
 544          $u2 = $dg->create_user();
 545  
 546          $this->setAdminUser();
 547          $tpl1 = $lpg->create_template();
 548          $tpl2 = $lpg->create_template();
 549          $up1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id')));
 550          $up2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => null));
 551  
 552          try {
 553              // Trying to remove the template dependency.
 554              $record = $up1->to_record();
 555              $record->templateid = null;
 556              api::update_plan($record);
 557              $this->fail('A plan cannot be unlinked using api::update_plan()');
 558          } catch (coding_exception $e) {
 559              // All good.
 560          }
 561  
 562          try {
 563              // Trying to switch to another template.
 564              $record = $up1->to_record();
 565              $record->templateid = $tpl2->get('id');
 566              api::update_plan($record);
 567              $this->fail('A plan cannot be moved to another template.');
 568          } catch (coding_exception $e) {
 569              // All good.
 570          }
 571  
 572          try {
 573              // Trying to switch to using a template.
 574              $record = $up2->to_record();
 575              $record->templateid = $tpl1->get('id');
 576              api::update_plan($record);
 577              $this->fail('A plan cannot be update to use a template.');
 578          } catch (coding_exception $e) {
 579              // All good.
 580          }
 581      }
 582  
 583      public function test_unlink_plan_from_template() {
 584          $this->resetAfterTest(true);
 585          $dg = $this->getDataGenerator();
 586          $lpg = $dg->get_plugin_generator('core_competency');
 587          $u1 = $dg->create_user();
 588          $u2 = $dg->create_user();
 589  
 590          $this->setAdminUser();
 591          $f1 = $lpg->create_framework();
 592          $f2 = $lpg->create_framework();
 593          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
 594          $c2a = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
 595          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
 596  
 597          $tpl1 = $lpg->create_template();
 598          $tpl2 = $lpg->create_template();
 599  
 600          $tplc1a = $lpg->create_template_competency(array('templateid' => $tpl1->get('id'), 'competencyid' => $c1a->get('id'),
 601              'sortorder' => 9));
 602          $tplc1b = $lpg->create_template_competency(array('templateid' => $tpl1->get('id'), 'competencyid' => $c1b->get('id'),
 603              'sortorder' => 8));
 604          $tplc2a = $lpg->create_template_competency(array('templateid' => $tpl2->get('id'), 'competencyid' => $c2a->get('id')));
 605  
 606          $plan1 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id'), 'status' => plan::STATUS_ACTIVE));
 607          $plan2 = $lpg->create_plan(array('userid' => $u2->id, 'templateid' => $tpl2->get('id')));
 608          $plan3 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get('id'), 'status' => plan::STATUS_COMPLETE));
 609  
 610          // Check that we have what we expect at this stage.
 611          $this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get('id'))));
 612          $this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get('id'))));
 613          $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan1->get('id'))));
 614          $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get('id'))));
 615          $this->assertTrue($plan1->is_based_on_template());
 616          $this->assertTrue($plan2->is_based_on_template());
 617  
 618          // Let's do this!
 619          $tpl1comps = \core_competency\template_competency::list_competencies($tpl1->get('id'), true);
 620          $tpl2comps = \core_competency\template_competency::list_competencies($tpl2->get('id'), true);
 621  
 622          api::unlink_plan_from_template($plan1);
 623  
 624          $plan1->read();
 625          $plan2->read();
 626          $this->assertCount(2, $tpl1comps);
 627          $this->assertCount(1, $tpl2comps);
 628          $this->assertEquals(2, \core_competency\template_competency::count_records(array('templateid' => $tpl1->get('id'))));
 629          $this->assertEquals(1, \core_competency\template_competency::count_records(array('templateid' => $tpl2->get('id'))));
 630          $this->assertEquals(2, \core_competency\plan_competency::count_records(array('planid' => $plan1->get('id'))));
 631          $this->assertEquals(0, \core_competency\plan_competency::count_records(array('planid' => $plan2->get('id'))));
 632          $this->assertFalse($plan1->is_based_on_template());
 633          $this->assertEquals($tpl1->get('id'), $plan1->get('origtemplateid'));
 634          $this->assertTrue($plan2->is_based_on_template());
 635          $this->assertEquals(null, $plan2->get('origtemplateid'));
 636  
 637          // Check we can unlink draft plan.
 638          try {
 639              api::unlink_plan_from_template($plan2);
 640          } catch (coding_exception $e) {
 641              $this->fail('Fail to unlink draft plan.');
 642          }
 643  
 644          // Check we can not unlink completed plan.
 645          try {
 646              api::unlink_plan_from_template($plan3);
 647              $this->fail('We can not unlink completed plan.');
 648          } catch (coding_exception $e) {
 649              // All good.
 650          }
 651  
 652          // Even the order remains.
 653          $plan1comps = \core_competency\plan_competency::list_competencies($plan1->get('id'));
 654          $before = reset($tpl1comps);
 655          $after = reset($plan1comps);
 656          $this->assertEquals($before->get('id'), $after->get('id'));
 657          $this->assertEquals($before->get('sortorder'), $after->get('sortorder'));
 658          $before = next($tpl1comps);
 659          $after = next($plan1comps);
 660          $this->assertEquals($before->get('id'), $after->get('id'));
 661          $this->assertEquals($before->get('sortorder'), $after->get('sortorder'));
 662      }
 663  
 664      public function test_update_template_updates_plans() {
 665          $this->resetAfterTest(true);
 666          $this->setAdminUser();
 667  
 668          $dg = $this->getDataGenerator();
 669          $u1 = $dg->create_user();
 670          $u2 = $dg->create_user();
 671          $lpg = $dg->get_plugin_generator('core_competency');
 672          $tpl1 = $lpg->create_template();
 673          $tpl2 = $lpg->create_template();
 674  
 675          // Create plans with data not matching templates.
 676          $time = time();
 677          $plan1 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $u1->id,
 678              'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_MARKDOWN));
 679          $plan2 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $u2->id,
 680              'name' => 'Not right name', 'duedate' => $time + 3601, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
 681          $plan3 = $lpg->create_plan(array('templateid' => $tpl2->get('id'), 'userid' => $u1->id,
 682              'name' => 'Not sweet name', 'duedate' => $time + 3602, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
 683  
 684          // Prepare our expectations.
 685          $plan1->read();
 686          $plan2->read();
 687          $plan3->read();
 688  
 689          $this->assertEquals($tpl1->get('id'), $plan1->get('templateid'));
 690          $this->assertEquals($tpl1->get('id'), $plan2->get('templateid'));
 691          $this->assertEquals($tpl2->get('id'), $plan3->get('templateid'));
 692          $this->assertNotEquals($tpl1->get('shortname'), $plan1->get('name'));
 693          $this->assertNotEquals($tpl1->get('shortname'), $plan2->get('name'));
 694          $this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));
 695          $this->assertNotEquals($tpl1->get('description'), $plan1->get('description'));
 696          $this->assertNotEquals($tpl1->get('description'), $plan2->get('description'));
 697          $this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));
 698          $this->assertNotEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));
 699          $this->assertNotEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));
 700          $this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));
 701          $this->assertNotEquals($tpl1->get('duedate'), $plan1->get('duedate'));
 702          $this->assertNotEquals($tpl1->get('duedate'), $plan2->get('duedate'));
 703          $this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));
 704  
 705          // Update the template without changing critical fields does not update the plans.
 706          $data = $tpl1->to_record();
 707          $data->visible = 0;
 708          api::update_template($data);
 709          $this->assertNotEquals($tpl1->get('shortname'), $plan1->get('name'));
 710          $this->assertNotEquals($tpl1->get('shortname'), $plan2->get('name'));
 711          $this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));
 712          $this->assertNotEquals($tpl1->get('description'), $plan1->get('description'));
 713          $this->assertNotEquals($tpl1->get('description'), $plan2->get('description'));
 714          $this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));
 715          $this->assertNotEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));
 716          $this->assertNotEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));
 717          $this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));
 718          $this->assertNotEquals($tpl1->get('duedate'), $plan1->get('duedate'));
 719          $this->assertNotEquals($tpl1->get('duedate'), $plan2->get('duedate'));
 720          $this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));
 721  
 722          // Now really update the template.
 723          $data = $tpl1->to_record();
 724          $data->shortname = 'Awesome!';
 725          $data->description = 'This is too awesome!';
 726          $data->descriptionformat = FORMAT_HTML;
 727          $data->duedate = $time + 200;
 728          api::update_template($data);
 729          $tpl1->read();
 730  
 731          // Now confirm that the right plans were updated.
 732          $plan1->read();
 733          $plan2->read();
 734          $plan3->read();
 735  
 736          $this->assertEquals($tpl1->get('id'), $plan1->get('templateid'));
 737          $this->assertEquals($tpl1->get('id'), $plan2->get('templateid'));
 738          $this->assertEquals($tpl2->get('id'), $plan3->get('templateid'));
 739  
 740          $this->assertEquals($tpl1->get('shortname'), $plan1->get('name'));
 741          $this->assertEquals($tpl1->get('shortname'), $plan2->get('name'));
 742          $this->assertNotEquals($tpl2->get('shortname'), $plan3->get('name'));
 743          $this->assertEquals($tpl1->get('description'), $plan1->get('description'));
 744          $this->assertEquals($tpl1->get('description'), $plan2->get('description'));
 745          $this->assertNotEquals($tpl2->get('description'), $plan3->get('description'));
 746          $this->assertEquals($tpl1->get('descriptionformat'), $plan1->get('descriptionformat'));
 747          $this->assertEquals($tpl1->get('descriptionformat'), $plan2->get('descriptionformat'));
 748          $this->assertNotEquals($tpl2->get('descriptionformat'), $plan3->get('descriptionformat'));
 749          $this->assertEquals($tpl1->get('duedate'), $plan1->get('duedate'));
 750          $this->assertEquals($tpl1->get('duedate'), $plan2->get('duedate'));
 751          $this->assertNotEquals($tpl2->get('duedate'), $plan3->get('duedate'));
 752      }
 753  
 754      /**
 755       * Test that the method to complete a plan.
 756       */
 757      public function test_complete_plan() {
 758          global $DB;
 759  
 760          $this->resetAfterTest(true);
 761          $this->setAdminUser();
 762          $dg = $this->getDataGenerator();
 763          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
 764          $user = $dg->create_user();
 765  
 766          // Create a framework and assign competencies.
 767          $framework = $lpg->create_framework();
 768          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 769          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 770          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 771          $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
 772  
 773          // Create two plans and assign competencies.
 774          $plan = $lpg->create_plan(array('userid' => $user->id));
 775          $otherplan = $lpg->create_plan(array('userid' => $user->id));
 776  
 777          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));
 778          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));
 779          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));
 780          $lpg->create_plan_competency(array('planid' => $otherplan->get('id'), 'competencyid' => $c1->get('id')));
 781  
 782          $uclist = array(
 783              $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id'),
 784                  'proficiency' => true, 'grade' => 1 )),
 785              $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id'),
 786                  'proficiency' => false, 'grade' => 2 ))
 787          );
 788  
 789          $this->assertEquals(2, \core_competency\user_competency::count_records());
 790          $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
 791  
 792          // Change status of the plan to complete.
 793          api::complete_plan($plan);
 794  
 795          // Check that user competencies are now in user_competency_plan objects and still in user_competency.
 796          $this->assertEquals(2, \core_competency\user_competency::count_records());
 797          $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
 798  
 799          $usercompetenciesplan = \core_competency\user_competency_plan::get_records();
 800  
 801          $this->assertEquals($uclist[0]->get('userid'), $usercompetenciesplan[0]->get('userid'));
 802          $this->assertEquals($uclist[0]->get('competencyid'), $usercompetenciesplan[0]->get('competencyid'));
 803          $this->assertEquals($uclist[0]->get('proficiency'), (bool) $usercompetenciesplan[0]->get('proficiency'));
 804          $this->assertEquals($uclist[0]->get('grade'), $usercompetenciesplan[0]->get('grade'));
 805          $this->assertEquals($plan->get('id'), $usercompetenciesplan[0]->get('planid'));
 806  
 807          $this->assertEquals($uclist[1]->get('userid'), $usercompetenciesplan[1]->get('userid'));
 808          $this->assertEquals($uclist[1]->get('competencyid'), $usercompetenciesplan[1]->get('competencyid'));
 809          $this->assertEquals($uclist[1]->get('proficiency'), (bool) $usercompetenciesplan[1]->get('proficiency'));
 810          $this->assertEquals($uclist[1]->get('grade'), $usercompetenciesplan[1]->get('grade'));
 811          $this->assertEquals($plan->get('id'), $usercompetenciesplan[1]->get('planid'));
 812  
 813          $this->assertEquals($user->id, $usercompetenciesplan[2]->get('userid'));
 814          $this->assertEquals($c3->get('id'), $usercompetenciesplan[2]->get('competencyid'));
 815          $this->assertNull($usercompetenciesplan[2]->get('proficiency'));
 816          $this->assertNull($usercompetenciesplan[2]->get('grade'));
 817          $this->assertEquals($plan->get('id'), $usercompetenciesplan[2]->get('planid'));
 818  
 819          // Check we can not add competency to completed plan.
 820          try {
 821              api::add_competency_to_plan($plan->get('id'), $c4->get('id'));
 822              $this->fail('We can not add competency to completed plan.');
 823          } catch (coding_exception $e) {
 824              // All good.
 825          }
 826  
 827          // Check we can not remove competency to completed plan.
 828          try {
 829              api::remove_competency_from_plan($plan->get('id'), $c3->get('id'));
 830              $this->fail('We can not remove competency to completed plan.');
 831          } catch (coding_exception $e) {
 832              // All good.
 833          }
 834  
 835          // Completing a plan that is completed throws an exception.
 836          $this->expectException(coding_exception::class);
 837          api::complete_plan($plan);
 838      }
 839  
 840      /**
 841       * Set-up the workflow data (review, active, ...).
 842       *
 843       * @return array
 844       */
 845      protected function setup_workflow_data() {
 846          $this->resetAfterTest();
 847  
 848          $dg = $this->getDataGenerator();
 849          $user = $dg->create_user();
 850          $reviewer = $dg->create_user();
 851          $otheruser = $dg->create_user();
 852  
 853          $syscontext = context_system::instance();
 854          $userrole = $dg->create_role();
 855          $reviewerrole = $dg->create_role();
 856          $otheruserrole = $dg->create_role();
 857  
 858          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $userrole, $syscontext->id);
 859          assign_capability('moodle/competency:planmanage', CAP_ALLOW, $reviewerrole, $syscontext->id);
 860          assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $reviewerrole, $syscontext->id);
 861          $dg->role_assign($userrole, $user->id, $syscontext->id);
 862          $dg->role_assign($reviewerrole, $reviewer->id, $syscontext->id);
 863          accesslib_clear_all_caches_for_unit_testing();
 864  
 865          $lpg = $dg->get_plugin_generator('core_competency');
 866          $tpl = $lpg->create_template();
 867          $plan = $lpg->create_plan(array('userid' => $user->id));
 868          $tplplan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tpl->get('id')));
 869  
 870          return array(
 871              'dg' => $dg,
 872              'lpg' => $lpg,
 873              'user' => $user,
 874              'reviewer' => $reviewer,
 875              'otheruser' => $otheruser,
 876              'plan' => $plan,
 877              'tplplan' => $tplplan,
 878          );
 879      }
 880  
 881      /**
 882       * Testing requesting the review of a plan.
 883       */
 884      public function test_plan_request_review() {
 885          $data = $this->setup_workflow_data();
 886          $dg = $data['dg'];
 887          $lpg = $data['lpg'];
 888          $user = $data['user'];
 889          $reviewer = $data['reviewer'];
 890          $otheruser = $data['otheruser'];
 891          $plan = $data['plan'];
 892          $tplplan = $data['tplplan'];
 893  
 894          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
 895          $this->assertEquals(plan::STATUS_DRAFT, $tplplan->get('status'));
 896  
 897          // Foreign user cannot do anything.
 898          $this->setUser($otheruser);
 899          try {
 900              api::plan_request_review($plan);
 901              $this->fail('The user can not read the plan.');
 902          } catch (required_capability_exception $e) {
 903              $this->assertEquals('nopermissions', $e->errorcode);
 904          }
 905  
 906          // Can not change a plan based on a template.
 907          $this->setUser($user);
 908          try {
 909              api::plan_request_review($tplplan);
 910              $this->fail('The plan is based on a template.');
 911          } catch (coding_exception $e) {
 912              $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
 913          }
 914  
 915          // Can not send for review when not draft.
 916          $this->setUser($user);
 917          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
 918          try {
 919              api::plan_request_review($plan);
 920              $this->fail('The plan cannot be sent for review at this stage.');
 921          } catch (coding_exception $e) {
 922              $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
 923          }
 924  
 925          // Can not send for review when not draft.
 926          $this->setUser($user);
 927          $plan->set('status', plan::STATUS_ACTIVE);
 928          try {
 929              api::plan_request_review($plan);
 930              $this->fail('The plan cannot be sent for review at this stage.');
 931          } catch (coding_exception $e) {
 932              $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
 933          }
 934  
 935          // Can not send for review when not draft.
 936          $this->setUser($user);
 937          $plan->set('status', plan::STATUS_IN_REVIEW);
 938          try {
 939              api::plan_request_review($plan);
 940              $this->fail('The plan cannot be sent for review at this stage.');
 941          } catch (coding_exception $e) {
 942              $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
 943          }
 944  
 945          // Can not send for review when not draft.
 946          $this->setUser($user);
 947          $plan->set('status', plan::STATUS_COMPLETE);
 948          try {
 949              api::plan_request_review($plan);
 950              $this->fail('The plan cannot be sent for review at this stage.');
 951          } catch (coding_exception $e) {
 952              $this->assertRegExp('/The plan cannot be sent for review at this stage./', $e->getMessage());
 953          }
 954  
 955          // Sending for review as a reviewer.
 956          $this->setUser($reviewer);
 957          $plan->set('status', plan::STATUS_DRAFT);
 958          try {
 959              api::plan_request_review($plan);
 960              $this->fail('The user can not request a review.');
 961          } catch (required_capability_exception $e) {
 962              $this->assertEquals('nopermissions', $e->errorcode);
 963          }
 964  
 965          // Sending for review.
 966          $this->setUser($user);
 967          api::plan_request_review($plan);
 968          $plan->read();
 969          $this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get('status'));
 970  
 971          // Sending for review by ID.
 972          $plan->set('status', plan::STATUS_DRAFT);
 973          $plan->update();
 974          api::plan_request_review($plan->get('id'));
 975          $plan->read();
 976          $this->assertEquals(plan::STATUS_WAITING_FOR_REVIEW, $plan->get('status'));
 977      }
 978  
 979      /**
 980       * Testing cancelling the review request.
 981       */
 982      public function test_plan_cancel_review_request() {
 983          $data = $this->setup_workflow_data();
 984          $dg = $data['dg'];
 985          $lpg = $data['lpg'];
 986          $user = $data['user'];
 987          $reviewer = $data['reviewer'];
 988          $otheruser = $data['otheruser'];
 989          $plan = $data['plan'];
 990          $tplplan = $data['tplplan'];
 991  
 992          // Set waiting for review.
 993          $tplplan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
 994          $tplplan->update();
 995          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
 996          $plan->update();
 997  
 998          // Foreign user cannot do anything.
 999          $this->setUser($otheruser);
1000          try {
1001              api::plan_cancel_review_request($plan);
1002              $this->fail('The user can not read the plan.');
1003          } catch (required_capability_exception $e) {
1004              $this->assertEquals('nopermissions', $e->errorcode);
1005          }
1006  
1007          // Can not change a plan based on a template.
1008          $this->setUser($user);
1009          try {
1010              api::plan_cancel_review_request($tplplan);
1011              $this->fail('The plan is based on a template.');
1012          } catch (coding_exception $e) {
1013              $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1014          }
1015  
1016          // Can not cancel review request when not waiting for review.
1017          $this->setUser($user);
1018          $plan->set('status', plan::STATUS_DRAFT);
1019          try {
1020              api::plan_cancel_review_request($plan);
1021              $this->fail('The plan cannot be sent for review at this stage.');
1022          } catch (coding_exception $e) {
1023              $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1024          }
1025  
1026          // Can not cancel review request when not waiting for review.
1027          $this->setUser($user);
1028          $plan->set('status', plan::STATUS_IN_REVIEW);
1029          try {
1030              api::plan_cancel_review_request($plan);
1031              $this->fail('The plan review cannot be cancelled at this stage.');
1032          } catch (coding_exception $e) {
1033              $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1034          }
1035  
1036          // Can not cancel review request when not waiting for review.
1037          $this->setUser($user);
1038          $plan->set('status', plan::STATUS_ACTIVE);
1039          try {
1040              api::plan_cancel_review_request($plan);
1041              $this->fail('The plan review cannot be cancelled at this stage.');
1042          } catch (coding_exception $e) {
1043              $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1044          }
1045  
1046          // Can not cancel review request when not waiting for review.
1047          $this->setUser($user);
1048          $plan->set('status', plan::STATUS_COMPLETE);
1049          try {
1050              api::plan_cancel_review_request($plan);
1051              $this->fail('The plan review cannot be cancelled at this stage.');
1052          } catch (coding_exception $e) {
1053              $this->assertRegExp('/The plan review cannot be cancelled at this stage./', $e->getMessage());
1054          }
1055  
1056          // Cancelling as a reviewer.
1057          $this->setUser($reviewer);
1058          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1059          try {
1060              api::plan_cancel_review_request($plan);
1061              $this->fail('The user can not cancel a review request.');
1062          } catch (required_capability_exception $e) {
1063              $this->assertEquals('nopermissions', $e->errorcode);
1064          }
1065  
1066          // Cancelling review request.
1067          $this->setUser($user);
1068          api::plan_cancel_review_request($plan);
1069          $plan->read();
1070          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1071  
1072          // Cancelling review request by ID.
1073          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1074          $plan->update();
1075          api::plan_cancel_review_request($plan->get('id'));
1076          $plan->read();
1077          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1078      }
1079  
1080      /**
1081       * Testing starting the review.
1082       */
1083      public function test_plan_start_review() {
1084          $data = $this->setup_workflow_data();
1085          $dg = $data['dg'];
1086          $lpg = $data['lpg'];
1087          $user = $data['user'];
1088          $reviewer = $data['reviewer'];
1089          $otheruser = $data['otheruser'];
1090          $plan = $data['plan'];
1091          $tplplan = $data['tplplan'];
1092  
1093          // Set waiting for review.
1094          $tplplan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1095          $tplplan->update();
1096          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1097          $plan->update();
1098  
1099          // Foreign user cannot do anything.
1100          $this->setUser($otheruser);
1101          try {
1102              api::plan_start_review($plan);
1103              $this->fail('The user can not read the plan.');
1104          } catch (required_capability_exception $e) {
1105              $this->assertEquals('nopermissions', $e->errorcode);
1106          }
1107  
1108          // Can not change a plan based on a template.
1109          $this->setUser($reviewer);
1110          try {
1111              api::plan_start_review($tplplan);
1112              $this->fail('The plan is based on a template.');
1113          } catch (coding_exception $e) {
1114              $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1115          }
1116  
1117          // Can not start a review when not waiting for review.
1118          $this->setUser($reviewer);
1119          $plan->set('status', plan::STATUS_DRAFT);
1120          try {
1121              api::plan_start_review($plan);
1122              $this->fail('The plan review cannot be started at this stage.');
1123          } catch (coding_exception $e) {
1124              $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1125          }
1126  
1127          // Can not start a review when not waiting for review.
1128          $this->setUser($reviewer);
1129          $plan->set('status', plan::STATUS_IN_REVIEW);
1130          try {
1131              api::plan_start_review($plan);
1132              $this->fail('The plan review cannot be started at this stage.');
1133          } catch (coding_exception $e) {
1134              $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1135          }
1136  
1137          // Can not start a review when not waiting for review.
1138          $this->setUser($reviewer);
1139          $plan->set('status', plan::STATUS_ACTIVE);
1140          try {
1141              api::plan_start_review($plan);
1142              $this->fail('The plan review cannot be started at this stage.');
1143          } catch (coding_exception $e) {
1144              $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1145          }
1146  
1147          // Can not start a review when not waiting for review.
1148          $this->setUser($reviewer);
1149          $plan->set('status', plan::STATUS_COMPLETE);
1150          try {
1151              api::plan_start_review($plan);
1152              $this->fail('The plan review cannot be started at this stage.');
1153          } catch (coding_exception $e) {
1154              $this->assertRegExp('/The plan review cannot be started at this stage./', $e->getMessage());
1155          }
1156  
1157          // Starting as the owner.
1158          $this->setUser($user);
1159          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1160          try {
1161              api::plan_start_review($plan);
1162              $this->fail('The user can not start a review.');
1163          } catch (required_capability_exception $e) {
1164              $this->assertEquals('nopermissions', $e->errorcode);
1165          }
1166  
1167          // Starting review.
1168          $this->setUser($reviewer);
1169          api::plan_start_review($plan);
1170          $plan->read();
1171          $this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get('status'));
1172          $this->assertEquals($reviewer->id, $plan->get('reviewerid'));
1173  
1174          // Starting review by ID.
1175          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1176          $plan->set('reviewerid', null);
1177          $plan->update();
1178          api::plan_start_review($plan->get('id'));
1179          $plan->read();
1180          $this->assertEquals(plan::STATUS_IN_REVIEW, $plan->get('status'));
1181          $this->assertEquals($reviewer->id, $plan->get('reviewerid'));
1182      }
1183  
1184      /**
1185       * Testing stopping the review.
1186       */
1187      public function test_plan_stop_review() {
1188          $data = $this->setup_workflow_data();
1189          $dg = $data['dg'];
1190          $lpg = $data['lpg'];
1191          $user = $data['user'];
1192          $reviewer = $data['reviewer'];
1193          $otheruser = $data['otheruser'];
1194          $plan = $data['plan'];
1195          $tplplan = $data['tplplan'];
1196  
1197          // Set waiting for review.
1198          $tplplan->set('status', plan::STATUS_IN_REVIEW);
1199          $tplplan->update();
1200          $plan->set('status', plan::STATUS_IN_REVIEW);
1201          $plan->update();
1202  
1203          // Foreign user cannot do anything.
1204          $this->setUser($otheruser);
1205          try {
1206              api::plan_stop_review($plan);
1207              $this->fail('The user can not read the plan.');
1208          } catch (required_capability_exception $e) {
1209              $this->assertEquals('nopermissions', $e->errorcode);
1210          }
1211  
1212          // Can not change a plan based on a template.
1213          $this->setUser($reviewer);
1214          try {
1215              api::plan_stop_review($tplplan);
1216              $this->fail('The plan is based on a template.');
1217          } catch (coding_exception $e) {
1218              $this->assertRegExp('/Template plans cannot be reviewed./', $e->getMessage());
1219          }
1220  
1221          // Can not stop a review whe not in review.
1222          $this->setUser($reviewer);
1223          $plan->set('status', plan::STATUS_DRAFT);
1224          try {
1225              api::plan_stop_review($plan);
1226              $this->fail('The plan review cannot be stopped at this stage.');
1227          } catch (coding_exception $e) {
1228              $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1229          }
1230  
1231          // Can not stop a review whe not in review.
1232          $this->setUser($reviewer);
1233          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1234          try {
1235              api::plan_stop_review($plan);
1236              $this->fail('The plan review cannot be stopped at this stage.');
1237          } catch (coding_exception $e) {
1238              $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1239          }
1240  
1241          // Can not stop a review whe not in review.
1242          $this->setUser($reviewer);
1243          $plan->set('status', plan::STATUS_ACTIVE);
1244          try {
1245              api::plan_stop_review($plan);
1246              $this->fail('The plan review cannot be stopped at this stage.');
1247          } catch (coding_exception $e) {
1248              $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1249          }
1250  
1251          // Can not stop a review whe not in review.
1252          $this->setUser($reviewer);
1253          $plan->set('status', plan::STATUS_COMPLETE);
1254          try {
1255              api::plan_stop_review($plan);
1256              $this->fail('The plan review cannot be stopped at this stage.');
1257          } catch (coding_exception $e) {
1258              $this->assertRegExp('/The plan review cannot be stopped at this stage./', $e->getMessage());
1259          }
1260  
1261          // Stopping as the owner.
1262          $this->setUser($user);
1263          $plan->set('status', plan::STATUS_IN_REVIEW);
1264          try {
1265              api::plan_stop_review($plan);
1266              $this->fail('The user can not stop a review.');
1267          } catch (required_capability_exception $e) {
1268              $this->assertEquals('nopermissions', $e->errorcode);
1269          }
1270  
1271          // Stopping review.
1272          $this->setUser($reviewer);
1273          api::plan_stop_review($plan);
1274          $plan->read();
1275          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1276  
1277          // Stopping review by ID.
1278          $plan->set('status', plan::STATUS_IN_REVIEW);
1279          $plan->update();
1280          api::plan_stop_review($plan->get('id'));
1281          $plan->read();
1282          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1283      }
1284  
1285      /**
1286       * Testing approving the plan.
1287       */
1288      public function test_approve_plan() {
1289          $data = $this->setup_workflow_data();
1290          $dg = $data['dg'];
1291          $lpg = $data['lpg'];
1292          $user = $data['user'];
1293          $reviewer = $data['reviewer'];
1294          $otheruser = $data['otheruser'];
1295          $plan = $data['plan'];
1296          $tplplan = $data['tplplan'];
1297  
1298          // Set waiting for review.
1299          $tplplan->set('status', plan::STATUS_IN_REVIEW);
1300          $tplplan->update();
1301          $plan->set('status', plan::STATUS_IN_REVIEW);
1302          $plan->update();
1303  
1304          // Foreign user cannot do anything.
1305          $this->setUser($otheruser);
1306          try {
1307              api::approve_plan($plan);
1308              $this->fail('The user can not read the plan.');
1309          } catch (required_capability_exception $e) {
1310              $this->assertEquals('nopermissions', $e->errorcode);
1311          }
1312  
1313          // Can not change a plan based on a template.
1314          $this->setUser($reviewer);
1315          try {
1316              api::approve_plan($tplplan);
1317              $this->fail('The plan is based on a template.');
1318          } catch (coding_exception $e) {
1319              $this->assertRegExp('/Template plans are already approved./', $e->getMessage());
1320          }
1321  
1322          // Can not approve a plan already approved.
1323          $this->setUser($reviewer);
1324          $plan->set('status', plan::STATUS_ACTIVE);
1325          try {
1326              api::approve_plan($plan);
1327              $this->fail('The plan cannot be approved at this stage.');
1328          } catch (coding_exception $e) {
1329              $this->assertRegExp('/The plan cannot be approved at this stage./', $e->getMessage());
1330          }
1331  
1332          // Can not approve a plan already approved.
1333          $this->setUser($reviewer);
1334          $plan->set('status', plan::STATUS_COMPLETE);
1335          try {
1336              api::approve_plan($plan);
1337              $this->fail('The plan cannot be approved at this stage.');
1338          } catch (coding_exception $e) {
1339              $this->assertRegExp('/The plan cannot be approved at this stage./', $e->getMessage());
1340          }
1341  
1342          // Approve as the owner.
1343          $this->setUser($user);
1344          $plan->set('status', plan::STATUS_IN_REVIEW);
1345          try {
1346              api::approve_plan($plan);
1347              $this->fail('The user can not approve the plan.');
1348          } catch (required_capability_exception $e) {
1349              $this->assertEquals('nopermissions', $e->errorcode);
1350          }
1351  
1352          // Approve plan from in review.
1353          $this->setUser($reviewer);
1354          api::approve_plan($plan);
1355          $plan->read();
1356          $this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));
1357  
1358          // Approve plan by ID.
1359          $plan->set('status', plan::STATUS_IN_REVIEW);
1360          $plan->update();
1361          api::approve_plan($plan->get('id'));
1362          $plan->read();
1363          $this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));
1364  
1365          // Approve plan from draft.
1366          $plan->set('status', plan::STATUS_DRAFT);
1367          $plan->update();
1368          api::approve_plan($plan);
1369          $plan->read();
1370          $this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));
1371  
1372          // Approve plan from waiting for review.
1373          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1374          $plan->update();
1375          api::approve_plan($plan);
1376          $plan->read();
1377          $this->assertEquals(plan::STATUS_ACTIVE, $plan->get('status'));
1378      }
1379  
1380      /**
1381       * Testing stopping the review.
1382       */
1383      public function test_unapprove_plan() {
1384          $data = $this->setup_workflow_data();
1385          $dg = $data['dg'];
1386          $lpg = $data['lpg'];
1387          $user = $data['user'];
1388          $reviewer = $data['reviewer'];
1389          $otheruser = $data['otheruser'];
1390          $plan = $data['plan'];
1391          $tplplan = $data['tplplan'];
1392  
1393          // Set waiting for review.
1394          $tplplan->set('status', plan::STATUS_ACTIVE);
1395          $tplplan->update();
1396          $plan->set('status', plan::STATUS_ACTIVE);
1397          $plan->update();
1398  
1399          // Foreign user cannot do anything.
1400          $this->setUser($otheruser);
1401          try {
1402              api::unapprove_plan($plan);
1403              $this->fail('The user can not read the plan.');
1404          } catch (required_capability_exception $e) {
1405              $this->assertEquals('nopermissions', $e->errorcode);
1406          }
1407  
1408          // Can not change a plan based on a template.
1409          $this->setUser($reviewer);
1410          try {
1411              api::unapprove_plan($tplplan);
1412              $this->fail('The plan is based on a template.');
1413          } catch (coding_exception $e) {
1414              $this->assertRegExp('/Template plans are always approved./', $e->getMessage());
1415          }
1416  
1417          // Can not unapprove a non-draft plan.
1418          $this->setUser($reviewer);
1419          $plan->set('status', plan::STATUS_DRAFT);
1420          try {
1421              api::unapprove_plan($plan);
1422              $this->fail('The plan cannot be sent back to draft at this stage.');
1423          } catch (coding_exception $e) {
1424              $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1425          }
1426  
1427          // Can not unapprove a non-draft plan.
1428          $this->setUser($reviewer);
1429          $plan->set('status', plan::STATUS_WAITING_FOR_REVIEW);
1430          try {
1431              api::unapprove_plan($plan);
1432              $this->fail('The plan cannot be sent back to draft at this stage.');
1433          } catch (coding_exception $e) {
1434              $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1435          }
1436  
1437          // Can not unapprove a non-draft plan.
1438          $this->setUser($reviewer);
1439          $plan->set('status', plan::STATUS_IN_REVIEW);
1440          try {
1441              api::unapprove_plan($plan);
1442              $this->fail('The plan cannot be sent back to draft at this stage.');
1443          } catch (coding_exception $e) {
1444              $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1445          }
1446  
1447          // Can not unapprove a non-draft plan.
1448          $this->setUser($reviewer);
1449          $plan->set('status', plan::STATUS_COMPLETE);
1450          try {
1451              api::unapprove_plan($plan);
1452              $this->fail('The plan cannot be sent back to draft at this stage.');
1453          } catch (coding_exception $e) {
1454              $this->assertRegExp('/The plan cannot be sent back to draft at this stage./', $e->getMessage());
1455          }
1456  
1457          // Unapprove as the owner.
1458          $this->setUser($user);
1459          $plan->set('status', plan::STATUS_ACTIVE);
1460          try {
1461              api::unapprove_plan($plan);
1462              $this->fail('The user can not unapprove the plan.');
1463          } catch (required_capability_exception $e) {
1464              $this->assertEquals('nopermissions', $e->errorcode);
1465          }
1466  
1467          // Unapprove plan.
1468          $this->setUser($reviewer);
1469          api::unapprove_plan($plan);
1470          $plan->read();
1471          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1472  
1473          // Unapprove plan by ID.
1474          $plan->set('status', plan::STATUS_ACTIVE);
1475          $plan->update();
1476          api::unapprove_plan($plan->get('id'));
1477          $plan->read();
1478          $this->assertEquals(plan::STATUS_DRAFT, $plan->get('status'));
1479      }
1480  
1481      /**
1482       * Test update plan and the managing of archived user competencies.
1483       */
1484      public function test_update_plan_manage_archived_competencies() {
1485          global $DB;
1486  
1487          $this->resetAfterTest(true);
1488          $dg = $this->getDataGenerator();
1489          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1490  
1491          $syscontext = context_system::instance();
1492  
1493          // Create users and roles for the test.
1494          $user = $dg->create_user();
1495          $manageownrole = $dg->create_role(array(
1496              'name' => 'User manage own',
1497              'shortname' => 'manageown'
1498          ));
1499          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);
1500          assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $manageownrole, $syscontext->id);
1501          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $manageownrole, $syscontext->id);
1502          assign_capability('moodle/competency:planviewown', CAP_ALLOW, $manageownrole, $syscontext->id);
1503          $dg->role_assign($manageownrole, $user->id, $syscontext->id);
1504          $this->setUser($user);
1505  
1506          // Create a framework and assign competencies.
1507          $framework = $lpg->create_framework();
1508          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1509          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1510          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1511  
1512          // Create two plans and assign competencies.
1513          $plan = $lpg->create_plan(array('userid' => $user->id));
1514          $otherplan = $lpg->create_plan(array('userid' => $user->id));
1515  
1516          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));
1517          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));
1518          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));
1519          $lpg->create_plan_competency(array('planid' => $otherplan->get('id'), 'competencyid' => $c1->get('id')));
1520  
1521          $uclist = array(
1522              $lpg->create_user_competency(array(
1523                                              'userid' => $user->id,
1524                                              'competencyid' => $c1->get('id'),
1525                                              'proficiency' => true,
1526                                              'grade' => 1
1527                                          )),
1528              $lpg->create_user_competency(array(
1529                                              'userid' => $user->id,
1530                                              'competencyid' => $c2->get('id'),
1531                                              'proficiency' => false,
1532                                              'grade' => 2
1533                                          ))
1534          );
1535  
1536          // Change status of the plan to complete.
1537          $record = $plan->to_record();
1538          $record->status = \core_competency\plan::STATUS_COMPLETE;
1539  
1540          try {
1541              $plan = api::update_plan($record);
1542              $this->fail('We cannot complete a plan using api::update_plan().');
1543          } catch (coding_exception $e) {
1544              // All good.
1545          }
1546          api::complete_plan($plan);
1547  
1548          // Check that user compretencies are now in user_competency_plan objects and still in user_competency.
1549          $this->assertEquals(2, \core_competency\user_competency::count_records());
1550          $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
1551  
1552          $usercompetenciesplan = \core_competency\user_competency_plan::get_records();
1553  
1554          $this->assertEquals($uclist[0]->get('userid'), $usercompetenciesplan[0]->get('userid'));
1555          $this->assertEquals($uclist[0]->get('competencyid'), $usercompetenciesplan[0]->get('competencyid'));
1556          $this->assertEquals($uclist[0]->get('proficiency'), (bool) $usercompetenciesplan[0]->get('proficiency'));
1557          $this->assertEquals($uclist[0]->get('grade'), $usercompetenciesplan[0]->get('grade'));
1558          $this->assertEquals($plan->get('id'), $usercompetenciesplan[0]->get('planid'));
1559  
1560          $this->assertEquals($uclist[1]->get('userid'), $usercompetenciesplan[1]->get('userid'));
1561          $this->assertEquals($uclist[1]->get('competencyid'), $usercompetenciesplan[1]->get('competencyid'));
1562          $this->assertEquals($uclist[1]->get('proficiency'), (bool) $usercompetenciesplan[1]->get('proficiency'));
1563          $this->assertEquals($uclist[1]->get('grade'), $usercompetenciesplan[1]->get('grade'));
1564          $this->assertEquals($plan->get('id'), $usercompetenciesplan[1]->get('planid'));
1565  
1566          $this->assertEquals($user->id, $usercompetenciesplan[2]->get('userid'));
1567          $this->assertEquals($c3->get('id'), $usercompetenciesplan[2]->get('competencyid'));
1568          $this->assertNull($usercompetenciesplan[2]->get('proficiency'));
1569          $this->assertNull($usercompetenciesplan[2]->get('grade'));
1570          $this->assertEquals($plan->get('id'), $usercompetenciesplan[2]->get('planid'));
1571  
1572          // Change status of the plan to active.
1573          $record = $plan->to_record();
1574          $record->status = \core_competency\plan::STATUS_ACTIVE;
1575  
1576          try {
1577              api::update_plan($record);
1578              $this->fail('Completed plan can not be edited');
1579          } catch (coding_exception $e) {
1580              // All good.
1581          }
1582  
1583          api::reopen_plan($record->id);
1584          // Check that user_competency_plan objects are deleted if the plan status is changed to another status.
1585          $this->assertEquals(2, \core_competency\user_competency::count_records());
1586          $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
1587      }
1588  
1589      /**
1590       * Test completing plan does not change the order of competencies.
1591       */
1592      public function test_complete_plan_doesnot_change_order() {
1593          global $DB;
1594  
1595          $this->resetAfterTest(true);
1596          $this->setAdminUser();
1597          $dg = $this->getDataGenerator();
1598          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1599  
1600          $syscontext = context_system::instance();
1601  
1602          // Create users and roles for the test.
1603          $user = $dg->create_user();
1604  
1605          // Create a framework and assign competencies.
1606          $framework = $lpg->create_framework();
1607          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1608          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1609          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1610  
1611          // Create two plans and assign competencies.
1612          $plan = $lpg->create_plan(array('userid' => $user->id));
1613  
1614          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c1->get('id')));
1615          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c2->get('id')));
1616          $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c3->get('id')));
1617  
1618          // Changing competencies order in plan competency.
1619          api::reorder_plan_competency($plan->get('id'), $c1->get('id'), $c3->get('id'));
1620  
1621          $competencies = api::list_plan_competencies($plan);
1622          $this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));
1623          $this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));
1624          $this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));
1625  
1626          // Completing plan.
1627          api::complete_plan($plan);
1628  
1629          $competencies = api::list_plan_competencies($plan);
1630  
1631          // Completing plan does not change order.
1632          $this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));
1633          $this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));
1634          $this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));
1635  
1636          // Testing plan based on template.
1637          $template = $lpg->create_template();
1638          $framework = $lpg->create_framework();
1639          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1640          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1641          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1642  
1643          $lpg->create_template_competency(array(
1644              'templateid' => $template->get('id'),
1645              'competencyid' => $c1->get('id')
1646          ));
1647          $lpg->create_template_competency(array(
1648              'templateid' => $template->get('id'),
1649              'competencyid' => $c2->get('id')
1650          ));
1651          $lpg->create_template_competency(array(
1652              'templateid' => $template->get('id'),
1653              'competencyid' => $c3->get('id')
1654          ));
1655          // Reorder competencies in template.
1656          api::reorder_template_competency($template->get('id'), $c1->get('id'), $c3->get('id'));
1657  
1658          // Create plan from template.
1659          $plan = api::create_plan_from_template($template->get('id'), $user->id);
1660  
1661          $competencies = api::list_plan_competencies($plan);
1662  
1663          // Completing plan does not change order.
1664          $this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));
1665          $this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));
1666          $this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));
1667  
1668          // Completing plan.
1669          api::complete_plan($plan);
1670  
1671          $competencies = api::list_plan_competencies($plan);
1672  
1673          // Completing plan does not change order.
1674          $this->assertEquals($c2->get('id'), $competencies[0]->competency->get('id'));
1675          $this->assertEquals($c3->get('id'), $competencies[1]->competency->get('id'));
1676          $this->assertEquals($c1->get('id'), $competencies[2]->competency->get('id'));
1677      }
1678  
1679      /**
1680       * Test remove plan and the managing of archived user competencies.
1681       */
1682      public function test_delete_plan_manage_archived_competencies() {
1683          $this->resetAfterTest(true);
1684          $dg = $this->getDataGenerator();
1685          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1686  
1687          $syscontext = context_system::instance();
1688  
1689          // Create user and role for the test.
1690          $user = $dg->create_user();
1691          $managerole = $dg->create_role(array(
1692              'name' => 'User manage own',
1693              'shortname' => 'manageown'
1694          ));
1695          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $managerole, $syscontext->id);
1696          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $managerole, $syscontext->id);
1697          $dg->role_assign($managerole, $user->id, $syscontext->id);
1698          $this->setUser($user);
1699  
1700          // Create a framework and assign competencies.
1701          $framework = $lpg->create_framework();
1702          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1703          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1704          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1705  
1706          // Create completed plan with records in user_competency.
1707          $completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));
1708  
1709          $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c1->get('id')));
1710          $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c2->get('id')));
1711  
1712          $uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));
1713          $uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id')));
1714  
1715          $ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get('id'),
1716                  'planid' => $completedplan->get('id')));
1717          $ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get('id'),
1718                  'planid' => $completedplan->get('id')));
1719  
1720          api::delete_plan($completedplan->get('id'));
1721  
1722          // Check that achived user competencies are deleted.
1723          $this->assertEquals(0, \core_competency\plan::count_records());
1724          $this->assertEquals(2, \core_competency\user_competency::count_records());
1725          $this->assertEquals(0, \core_competency\user_competency_plan::count_records());
1726      }
1727  
1728      /**
1729       * Test listing of plan competencies.
1730       */
1731      public function test_list_plan_competencies_manage_archived_competencies() {
1732          $this->resetAfterTest(true);
1733          $dg = $this->getDataGenerator();
1734          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1735  
1736          $syscontext = context_system::instance();
1737  
1738          // Create user and role for the test.
1739          $user = $dg->create_user();
1740          $viewrole = $dg->create_role(array(
1741              'name' => 'User view',
1742              'shortname' => 'view'
1743          ));
1744          assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $viewrole, $syscontext->id);
1745          assign_capability('moodle/competency:planview', CAP_ALLOW, $viewrole, $syscontext->id);
1746          $dg->role_assign($viewrole, $user->id, $syscontext->id);
1747          $this->setUser($user);
1748  
1749          // Create a framework and assign competencies.
1750          $framework = $lpg->create_framework();
1751          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1752          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1753          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1754  
1755          // Create draft plan with records in user_competency.
1756          $draftplan = $lpg->create_plan(array('userid' => $user->id));
1757  
1758          $lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c1->get('id')));
1759          $lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c2->get('id')));
1760          $lpg->create_plan_competency(array('planid' => $draftplan->get('id'), 'competencyid' => $c3->get('id')));
1761  
1762          $uc1 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));
1763          $uc2 = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c2->get('id')));
1764  
1765          // Check that user_competency objects are returned when plan status is not complete.
1766          $plancompetencies = api::list_plan_competencies($draftplan);
1767  
1768          $this->assertCount(3, $plancompetencies);
1769          $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[0]->usercompetency);
1770          $this->assertEquals($uc1->get('id'), $plancompetencies[0]->usercompetency->get('id'));
1771          $this->assertNull($plancompetencies[0]->usercompetencyplan);
1772  
1773          $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[1]->usercompetency);
1774          $this->assertEquals($uc2->get('id'), $plancompetencies[1]->usercompetency->get('id'));
1775          $this->assertNull($plancompetencies[1]->usercompetencyplan);
1776  
1777          $this->assertInstanceOf('\core_competency\user_competency', $plancompetencies[2]->usercompetency);
1778          $this->assertEquals(0, $plancompetencies[2]->usercompetency->get('id'));
1779          $this->assertNull($plancompetencies[2]->usercompetencyplan);
1780  
1781          // Create completed plan with records in user_competency_plan.
1782          $completedplan = $lpg->create_plan(array('userid' => $user->id, 'status' => \core_competency\plan::STATUS_COMPLETE));
1783  
1784          $pc1 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c1->get('id')));
1785          $pc2 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c2->get('id')));
1786          $pc3 = $lpg->create_plan_competency(array('planid' => $completedplan->get('id'), 'competencyid' => $c3->get('id')));
1787  
1788          $ucp1 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c1->get('id'),
1789                  'planid' => $completedplan->get('id')));
1790          $ucp2 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c2->get('id'),
1791                  'planid' => $completedplan->get('id')));
1792          $ucp3 = $lpg->create_user_competency_plan(array('userid' => $user->id, 'competencyid' => $c3->get('id'),
1793                  'planid' => $completedplan->get('id')));
1794  
1795          // Check that user_competency_plan objects are returned when plan status is complete.
1796          $plancompetencies = api::list_plan_competencies($completedplan);
1797  
1798          $this->assertCount(3, $plancompetencies);
1799          $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[0]->usercompetencyplan);
1800          $this->assertEquals($ucp1->get('id'), $plancompetencies[0]->usercompetencyplan->get('id'));
1801          $this->assertNull($plancompetencies[0]->usercompetency);
1802          $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[1]->usercompetencyplan);
1803          $this->assertEquals($ucp2->get('id'), $plancompetencies[1]->usercompetencyplan->get('id'));
1804          $this->assertNull($plancompetencies[1]->usercompetency);
1805          $this->assertInstanceOf('\core_competency\user_competency_plan', $plancompetencies[2]->usercompetencyplan);
1806          $this->assertEquals($ucp3->get('id'), $plancompetencies[2]->usercompetencyplan->get('id'));
1807          $this->assertNull($plancompetencies[2]->usercompetency);
1808      }
1809  
1810      public function test_create_template_cohort() {
1811          $this->resetAfterTest(true);
1812          $this->setAdminUser();
1813  
1814          $dg = $this->getDataGenerator();
1815          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1816  
1817          $c1 = $dg->create_cohort();
1818          $c2 = $dg->create_cohort();
1819          $t1 = $lpg->create_template();
1820          $t2 = $lpg->create_template();
1821  
1822          $this->assertEquals(0, \core_competency\template_cohort::count_records());
1823  
1824          // Create two relations with mixed parameters.
1825          $result = api::create_template_cohort($t1->get('id'), $c1->id);
1826          $result = api::create_template_cohort($t1, $c2);
1827  
1828          $this->assertEquals(2, \core_competency\template_cohort::count_records());
1829          $this->assertInstanceOf('core_competency\template_cohort', $result);
1830          $this->assertEquals($c2->id, $result->get('cohortid'));
1831          $this->assertEquals($t1->get('id'), $result->get('templateid'));
1832          $this->assertEquals(2, \core_competency\template_cohort::count_records_select('templateid = :id',
1833              array('id' => $t1->get('id'))));
1834          $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
1835              array('id' => $t2->get('id'))));
1836      }
1837  
1838      public function test_create_template_cohort_permissions() {
1839          $this->resetAfterTest(true);
1840  
1841          $dg = $this->getDataGenerator();
1842          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1843          $cat = $dg->create_category();
1844          $catcontext = context_coursecat::instance($cat->id);
1845          $syscontext = context_system::instance();
1846  
1847          $user = $dg->create_user();
1848          $role = $dg->create_role();
1849          assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);
1850          $dg->role_assign($role, $user->id, $syscontext->id);
1851  
1852          $cohortrole = $dg->create_role();
1853          assign_capability('moodle/cohort:view', CAP_ALLOW, $cohortrole, $syscontext->id, true);
1854  
1855          accesslib_clear_all_caches_for_unit_testing();
1856  
1857          $c1 = $dg->create_cohort();
1858          $c2 = $dg->create_cohort(array('visible' => 0, 'contextid' => $catcontext->id));
1859          $t1 = $lpg->create_template();
1860  
1861          $this->assertEquals(0, \core_competency\template_cohort::count_records());
1862  
1863          $this->setUser($user);
1864          $result = api::create_template_cohort($t1, $c1);
1865          $this->assertInstanceOf('core_competency\\template_cohort', $result);
1866  
1867          try {
1868              $result = api::create_template_cohort($t1, $c2);
1869              $this->fail('Permission required.');
1870          } catch (required_capability_exception $e) {
1871              // That's what should happen.
1872          }
1873  
1874          // Try again with the right permissions.
1875          $dg->role_assign($cohortrole, $user->id, $catcontext->id);
1876          accesslib_clear_all_caches_for_unit_testing();
1877  
1878          $result = api::create_template_cohort($t1, $c2);
1879          $this->assertInstanceOf('core_competency\\template_cohort', $result);
1880      }
1881  
1882      public function test_reorder_template_competencies_permissions() {
1883          $this->resetAfterTest(true);
1884  
1885          $dg = $this->getDataGenerator();
1886          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1887          $cat = $dg->create_category();
1888          $catcontext = context_coursecat::instance($cat->id);
1889          $syscontext = context_system::instance();
1890  
1891          $user = $dg->create_user();
1892          $role = $dg->create_role();
1893          assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $syscontext->id, true);
1894          $dg->role_assign($role, $user->id, $syscontext->id);
1895  
1896          // Create a template.
1897          $template = $lpg->create_template(array('contextid' => $catcontext->id));
1898  
1899          // Create a competency framework.
1900          $framework = $lpg->create_framework(array('contextid' => $catcontext->id));
1901  
1902          // Create competencies.
1903          $competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1904          $competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1905  
1906          // Add the competencies.
1907          $lpg->create_template_competency(array(
1908              'templateid' => $template->get('id'),
1909              'competencyid' => $competency1->get('id')
1910          ));
1911          $lpg->create_template_competency(array(
1912              'templateid' => $template->get('id'),
1913              'competencyid' => $competency2->get('id')
1914          ));
1915          $this->setUser($user);
1916          // Can reorder competencies with system context permissions in category context.
1917          $result = api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));
1918          $this->assertTrue($result);
1919          unassign_capability('moodle/competency:templatemanage', $role, $syscontext->id);
1920          accesslib_clear_all_caches_for_unit_testing();
1921  
1922          try {
1923              api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));
1924              $this->fail('Exception expected due to not permissions to manage template competencies');
1925          } catch (required_capability_exception $e) {
1926              $this->assertEquals('nopermissions', $e->errorcode);
1927          }
1928  
1929          // Giving permissions in category context.
1930          assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $role, $catcontext->id, true);
1931          $dg->role_assign($role, $user->id, $catcontext->id);
1932          // User with templatemanage capability in category context can reorder competencies in temple.
1933          $result = api::reorder_template_competency($template->get('id'), $competency1->get('id'), $competency2->get('id'));
1934          $this->assertTrue($result);
1935          // Removing templatemanage capability in category context.
1936          unassign_capability('moodle/competency:templatemanage', $role, $catcontext->id);
1937          accesslib_clear_all_caches_for_unit_testing();
1938  
1939          try {
1940              api::reorder_template_competency($template->get('id'), $competency2->get('id'), $competency1->get('id'));
1941              $this->fail('Exception expected due to not permissions to manage template competencies');
1942          } catch (required_capability_exception $e) {
1943              $this->assertEquals('nopermissions', $e->errorcode);
1944          }
1945      }
1946  
1947      public function test_delete_template() {
1948          $this->resetAfterTest(true);
1949          $this->setAdminUser();
1950  
1951          $dg = $this->getDataGenerator();
1952          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1953  
1954          $c1 = $dg->create_cohort();
1955          $c2 = $dg->create_cohort();
1956          $template = $lpg->create_template();
1957          $id = $template->get('id');
1958  
1959          // Create 2 template cohorts.
1960          $tc1 = $lpg->create_template_cohort(array('templateid' => $template->get('id'), 'cohortid' => $c1->id));
1961          $tc1 = $lpg->create_template_cohort(array('templateid' => $template->get('id'), 'cohortid' => $c2->id));
1962  
1963          // Check pre-test.
1964          $this->assertTrue(\core_competency\template::record_exists($id));
1965          $this->assertEquals(2, \core_competency\template_cohort::count_records(array('templateid' => $id)));
1966  
1967          $result = api::delete_template($template->get('id'));
1968          $this->assertTrue($result);
1969  
1970          // Check that the template deos not exist anymore.
1971          $this->assertFalse(\core_competency\template::record_exists($id));
1972  
1973          // Test if associated cohorts are also deleted.
1974          $this->assertEquals(0, \core_competency\template_cohort::count_records(array('templateid' => $id)));
1975      }
1976  
1977      public function test_delete_template_cohort() {
1978          $this->resetAfterTest(true);
1979          $this->setAdminUser();
1980  
1981          $dg = $this->getDataGenerator();
1982          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1983  
1984          $c1 = $dg->create_cohort();
1985          $c2 = $dg->create_cohort();
1986          $t1 = $lpg->create_template();
1987          $t2 = $lpg->create_template();
1988          $tc1 = $lpg->create_template_cohort(array('templateid' => $t1->get('id'), 'cohortid' => $c1->id));
1989          $tc1 = $lpg->create_template_cohort(array('templateid' => $t2->get('id'), 'cohortid' => $c2->id));
1990  
1991          $this->assertEquals(2, \core_competency\template_cohort::count_records());
1992          $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1993              array('id' => $t1->get('id'))));
1994          $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
1995              array('id' => $t2->get('id'))));
1996  
1997          // Delete existing.
1998          $result = api::delete_template_cohort($t1->get('id'), $c1->id);
1999          $this->assertTrue($result);
2000          $this->assertEquals(1, \core_competency\template_cohort::count_records());
2001          $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
2002              array('id' => $t1->get('id'))));
2003          $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
2004              array('id' => $t2->get('id'))));
2005  
2006          // Delete non-existant.
2007          $result = api::delete_template_cohort($t1->get('id'), $c1->id);
2008          $this->assertTrue($result);
2009          $this->assertEquals(1, \core_competency\template_cohort::count_records());
2010          $this->assertEquals(0, \core_competency\template_cohort::count_records_select('templateid = :id',
2011              array('id' => $t1->get('id'))));
2012          $this->assertEquals(1, \core_competency\template_cohort::count_records_select('templateid = :id',
2013              array('id' => $t2->get('id'))));
2014      }
2015  
2016      public function test_add_evidence_log() {
2017          $this->resetAfterTest(true);
2018          $dg = $this->getDataGenerator();
2019          $lpg = $dg->get_plugin_generator('core_competency');
2020  
2021          $u1 = $dg->create_user();
2022          $u1ctx = context_user::instance($u1->id);
2023          $f1 = $lpg->create_framework();
2024          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2025          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2026  
2027          // Creating a standard evidence with minimal information.
2028          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG,
2029              'invaliddata', 'error');
2030          $evidence->read();
2031          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2032          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2033          $this->assertSame(null, $uc->get('grade'));
2034          $this->assertSame(null, $uc->get('proficiency'));
2035          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2036          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2037          $this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get('action'));
2038          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2039          $this->assertEquals('error', $evidence->get('desccomponent'));
2040          $this->assertSame(null, $evidence->get('desca'));
2041          $this->assertSame(null, $evidence->get('url'));
2042          $this->assertSame(null, $evidence->get('grade'));
2043          $this->assertSame(null, $evidence->get('actionuserid'));
2044  
2045          // Creating a standard evidence with more information.
2046          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2047              'error', '$a', false, 'http://moodle.org', null, 2, 'The evidence of prior learning were reviewed.');
2048          $evidence->read();
2049          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2050          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2051          $this->assertSame(null, $uc->get('grade'));
2052          $this->assertSame(null, $uc->get('proficiency'));
2053          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2054          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2055          $this->assertEquals(\core_competency\evidence::ACTION_LOG, $evidence->get('action'));
2056          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2057          $this->assertEquals('error', $evidence->get('desccomponent'));
2058          $this->assertEquals('$a', $evidence->get('desca'));
2059          $this->assertEquals('http://moodle.org', $evidence->get('url'));
2060          $this->assertSame(null, $evidence->get('grade'));
2061          $this->assertEquals(2, $evidence->get('actionuserid'));
2062          $this->assertSame('The evidence of prior learning were reviewed.', $evidence->get('note'));
2063  
2064          // Creating a standard evidence and send for review.
2065          $evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2066              'error', null, true);
2067          $evidence->read();
2068          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));
2069          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));
2070  
2071          // Trying to pass a grade should fail.
2072          try {
2073              $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2074                  'error', null, false, null, 1);
2075              $this->fail('A grade can not be set');
2076          } catch (coding_exception $e) {
2077              $this->assertRegExp('/grade MUST NOT be set/', $e->getMessage());
2078          }
2079      }
2080  
2081      public function test_add_evidence_complete() {
2082          $this->resetAfterTest(true);
2083          $dg = $this->getDataGenerator();
2084          $lpg = $dg->get_plugin_generator('core_competency');
2085  
2086          $u1 = $dg->create_user();
2087          $u1ctx = context_user::instance($u1->id);
2088          $scale = $dg->create_scale(array('scale' => 'A,B,C,D'));
2089          $scaleconfig = array(array('scaleid' => $scale->id));
2090          $scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 1, 'proficient' => 0);
2091          $scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 1);
2092          $scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 0, 'proficient' => 1);
2093          $c2scaleconfig = array(array('scaleid' => $scale->id));
2094          $c2scaleconfig[] = array('name' => 'B', 'id' => 2, 'scaledefault' => 0, 'proficient' => 1);
2095          $c2scaleconfig[] = array('name' => 'C', 'id' => 3, 'scaledefault' => 0, 'proficient' => 0);
2096          $c2scaleconfig[] = array('name' => 'D', 'id' => 4, 'scaledefault' => 1, 'proficient' => 1);
2097          $f1 = $lpg->create_framework(array('scaleid' => $scale->id, 'scaleconfiguration' => $scaleconfig));
2098          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2099          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'scaleid' => $scale->id,
2100              'scaleconfiguration' => $c2scaleconfig));
2101          $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2102  
2103          // Creating an evidence with minimal information.
2104          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2105              'error');
2106          $evidence->read();
2107          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2108          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2109          $this->assertEquals(2, $uc->get('grade'));    // The grade has been set automatically to the framework default.
2110          $this->assertEquals(0, $uc->get('proficiency'));
2111          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2112          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2113          $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));
2114          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2115          $this->assertEquals('error', $evidence->get('desccomponent'));
2116          $this->assertSame(null, $evidence->get('desca'));
2117          $this->assertSame(null, $evidence->get('url'));
2118          $this->assertEquals(2, $evidence->get('grade'));
2119          $this->assertSame(null, $evidence->get('actionuserid'));
2120  
2121          // Creating an evidence complete on competency with custom scale.
2122          $evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2123              'error');
2124          $evidence->read();
2125          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));
2126          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2127          $this->assertEquals(4, $uc->get('grade'));    // The grade has been set automatically to the competency default.
2128          $this->assertEquals(true, $uc->get('proficiency'));
2129          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2130          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2131          $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));
2132          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2133          $this->assertEquals('error', $evidence->get('desccomponent'));
2134          $this->assertSame(null, $evidence->get('desca'));
2135          $this->assertSame(null, $evidence->get('url'));
2136          $this->assertEquals(4, $evidence->get('grade'));
2137          $this->assertSame(null, $evidence->get('actionuserid'));
2138  
2139          // Creating an evidence complete on a user competency with an existing grade.
2140          $uc = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c3->get('id'), 'grade' => 1,
2141              'proficiency' => 0));
2142          $this->assertEquals(1, $uc->get('grade'));
2143          $this->assertEquals(0, $uc->get('proficiency'));
2144          $evidence = api::add_evidence($u1->id, $c3->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2145              'error');
2146          $evidence->read();
2147          $uc->read();
2148          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2149          $this->assertEquals(1, $uc->get('grade'));    // The grade has not been changed.
2150          $this->assertEquals(0, $uc->get('proficiency'));
2151          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2152          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2153          $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $evidence->get('action'));
2154          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2155          $this->assertEquals('error', $evidence->get('desccomponent'));
2156          $this->assertSame(null, $evidence->get('desca'));
2157          $this->assertSame(null, $evidence->get('url'));
2158          $this->assertEquals(2, $evidence->get('grade'));     // The complete grade has been set.
2159          $this->assertSame(null, $evidence->get('actionuserid'));
2160  
2161          // Creating a standard evidence and send for review.
2162          $evidence = api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2163              'error', null, true);
2164          $evidence->read();
2165          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));
2166          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));
2167  
2168          // Trying to pass a grade should throw an exception.
2169          try {
2170              api::add_evidence($u1->id, $c2->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_COMPLETE, 'invaliddata',
2171                  'error', null, false, null, 1);
2172          } catch (coding_exception $e) {
2173              $this->assertRegExp('/grade MUST NOT be set/', $e->getMessage());
2174          }
2175      }
2176  
2177      public function test_add_evidence_override() {
2178          $this->resetAfterTest(true);
2179          $dg = $this->getDataGenerator();
2180          $lpg = $dg->get_plugin_generator('core_competency');
2181  
2182          $u1 = $dg->create_user();
2183          $u1ctx = context_user::instance($u1->id);
2184          $f1 = $lpg->create_framework();
2185          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2186  
2187          // Creating an evidence with minimal information.
2188          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2189              'error');
2190          $evidence->read();
2191          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2192          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2193          $this->assertSame(null, $uc->get('grade'));      // We overrode with 'null'.
2194          $this->assertSame(null, $uc->get('proficiency'));
2195          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2196          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2197          $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));
2198          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2199          $this->assertEquals('error', $evidence->get('desccomponent'));
2200          $this->assertSame(null, $evidence->get('desca'));
2201          $this->assertSame(null, $evidence->get('url'));
2202          $this->assertSame(null, $evidence->get('grade')); // We overrode with 'null'.
2203          $this->assertSame(null, $evidence->get('actionuserid'));
2204  
2205          // Creating an evidence with a grade information.
2206          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2207              'error', null, false, null, 3);
2208          $evidence->read();
2209          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2210          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2211          $this->assertEquals(3, $uc->get('grade'));
2212          $this->assertEquals(true, $uc->get('proficiency'));
2213          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2214          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2215          $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));
2216          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2217          $this->assertEquals('error', $evidence->get('desccomponent'));
2218          $this->assertSame(null, $evidence->get('desca'));
2219          $this->assertSame(null, $evidence->get('url'));
2220          $this->assertEquals(3, $evidence->get('grade'));
2221          $this->assertSame(null, $evidence->get('actionuserid'));
2222  
2223          // Creating an evidence with another grade information.
2224          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2225              'error', null, false, null, 1);
2226          $evidence->read();
2227          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2228          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc->get('status'));
2229          $this->assertEquals(1, $uc->get('grade'));
2230          $this->assertEquals(0, $uc->get('proficiency'));
2231          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2232          $this->assertEquals($u1ctx->id, $evidence->get('contextid'));
2233          $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));
2234          $this->assertEquals('invaliddata', $evidence->get('descidentifier'));
2235          $this->assertEquals('error', $evidence->get('desccomponent'));
2236          $this->assertSame(null, $evidence->get('desca'));
2237          $this->assertSame(null, $evidence->get('url'));
2238          $this->assertEquals(1, $evidence->get('grade'));
2239          $this->assertSame(null, $evidence->get('actionuserid'));
2240  
2241          // Creating reverting the grade and send for review.
2242          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_OVERRIDE, 'invaliddata',
2243              'error', null, true);
2244          $evidence->read();
2245          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2246          $this->assertSame(null, $uc->get('grade'));
2247          $this->assertSame(null, $uc->get('proficiency'));
2248          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));
2249          $this->assertSame(null, $evidence->get('grade'));
2250      }
2251  
2252      public function test_add_evidence_and_send_for_review() {
2253          $this->resetAfterTest(true);
2254          $dg = $this->getDataGenerator();
2255          $lpg = $dg->get_plugin_generator('core_competency');
2256  
2257          $u1 = $dg->create_user();
2258          $u1ctx = context_user::instance($u1->id);
2259          $f1 = $lpg->create_framework();
2260          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2261  
2262          // Non-existing user competencies are created up for review.
2263          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2264              'error', null, true);
2265          $uc = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2266          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));
2267  
2268          // Existing user competencies sent for review don't change.
2269          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2270              'error', null, true);
2271          $uc->read();
2272          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc->get('status'));
2273  
2274          // A user competency with a status non-idle won't change.
2275          $uc->set('status', \core_competency\user_competency::STATUS_IN_REVIEW);
2276          $uc->update();
2277          $evidence = api::add_evidence($u1->id, $c1->get('id'), $u1ctx->id, \core_competency\evidence::ACTION_LOG, 'invaliddata',
2278              'error', null, true);
2279          $uc->read();
2280          $this->assertEquals(\core_competency\user_competency::STATUS_IN_REVIEW, $uc->get('status'));
2281      }
2282  
2283      /**
2284       * Test add evidence for existing user_competency.
2285       */
2286      public function test_add_evidence_existing_user_competency() {
2287          $this->resetAfterTest(true);
2288          $dg = $this->getDataGenerator();
2289          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2290  
2291          $syscontext = context_system::instance();
2292  
2293          // Create users.
2294          $user = $dg->create_user();
2295          $this->setUser($user);
2296  
2297          // Create a framework and assign competencies.
2298          $framework = $lpg->create_framework();
2299          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2300          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2301          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2302          $uc = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));
2303          $this->assertSame(null, $uc->get('grade'));
2304          $this->assertSame(null, $uc->get('proficiency'));
2305  
2306          // Create an evidence and check it was created with the right usercomptencyid and information.
2307          $evidence = api::add_evidence($user->id, $c1->get('id'), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,
2308              'invalidevidencedesc', 'core_competency', array('a' => 'b'), false, 'http://moodle.org', 1, 2);
2309          $this->assertEquals(1, \core_competency\evidence::count_records());
2310  
2311          $evidence->read();
2312          $uc->read();
2313          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2314          $this->assertEquals('invalidevidencedesc', $evidence->get('descidentifier'));
2315          $this->assertEquals('core_competency', $evidence->get('desccomponent'));
2316          $this->assertEquals((object) array('a' => 'b'), $evidence->get('desca'));
2317          $this->assertEquals('http://moodle.org', $evidence->get('url'));
2318          $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));
2319          $this->assertEquals(2, $evidence->get('actionuserid'));
2320          $this->assertEquals(1, $evidence->get('grade'));
2321          $this->assertEquals(1, $uc->get('grade'));
2322          $this->assertEquals(0, $uc->get('proficiency'));
2323      }
2324  
2325      /**
2326       * Test add evidence for non-existing user_competency.
2327       */
2328      public function test_add_evidence_no_existing_user_competency() {
2329          $this->resetAfterTest(true);
2330          $dg = $this->getDataGenerator();
2331          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2332  
2333          $syscontext = context_system::instance();
2334  
2335          // Create users.
2336          $user = $dg->create_user();
2337          $this->setUser($user);
2338  
2339          // Create a framework and assign competencies.
2340          $framework = $lpg->create_framework();
2341          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2342          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2343          $this->assertEquals(0, \core_competency\user_competency::count_records());
2344  
2345          // Create an evidence without a user competency record.
2346          $evidence = api::add_evidence($user->id, $c1->get('id'), $syscontext->id, \core_competency\evidence::ACTION_OVERRIDE,
2347              'invalidevidencedesc', 'core_competency', 'Hello world!', false, 'http://moodle.org', 1, 2);
2348          $this->assertEquals(1, \core_competency\evidence::count_records());
2349          $this->assertEquals(1, \core_competency\user_competency::count_records());
2350  
2351          $uc = \core_competency\user_competency::get_record(array('userid' => $user->id, 'competencyid' => $c1->get('id')));
2352          $evidence->read();
2353          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
2354          $this->assertEquals('invalidevidencedesc', $evidence->get('descidentifier'));
2355          $this->assertEquals('core_competency', $evidence->get('desccomponent'));
2356          $this->assertEquals('Hello world!', $evidence->get('desca'));
2357          $this->assertEquals('http://moodle.org', $evidence->get('url'));
2358          $this->assertEquals(\core_competency\evidence::ACTION_OVERRIDE, $evidence->get('action'));
2359          $this->assertEquals(2, $evidence->get('actionuserid'));
2360          $this->assertEquals(1, $evidence->get('grade'));
2361          $this->assertEquals(1, $uc->get('grade'));
2362          $this->assertEquals(0, $uc->get('proficiency'));
2363      }
2364  
2365      public function test_add_evidence_applies_competency_rules() {
2366          $this->resetAfterTest(true);
2367          $dg = $this->getDataGenerator();
2368          $lpg = $dg->get_plugin_generator('core_competency');
2369          $syscontext = context_system::instance();
2370          $ctxid = $syscontext->id;
2371  
2372          $u1 = $dg->create_user();
2373  
2374          // Setting up the framework.
2375          $f1 = $lpg->create_framework();
2376          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2377          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
2378          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
2379          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2380          $c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c2->get('id')));
2381          $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2382          $c3a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c3->get('id')));
2383          $c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2384          $c4a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c4->get('id')));
2385          $c5 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2386  
2387          // Setting up the rules.
2388          $c1->set('ruletype', 'core_competency\\competency_rule_all');
2389          $c1->set('ruleoutcome', \core_competency\competency::OUTCOME_COMPLETE);
2390          $c1->update();
2391          $c2->set('ruletype', 'core_competency\\competency_rule_all');
2392          $c2->set('ruleoutcome', \core_competency\competency::OUTCOME_RECOMMEND);
2393          $c2->update();
2394          $c3->set('ruletype', 'core_competency\\competency_rule_all');
2395          $c3->set('ruleoutcome', \core_competency\competency::OUTCOME_EVIDENCE);
2396          $c3->update();
2397          $c4->set('ruletype', 'core_competency\\competency_rule_all');
2398          $c4->set('ruleoutcome', \core_competency\competency::OUTCOME_NONE);
2399          $c4->update();
2400  
2401          // Confirm the current data.
2402          $this->assertEquals(0, user_competency::count_records());
2403          $this->assertEquals(0, evidence::count_records());
2404  
2405          // Let's do this!
2406          // First let's confirm that evidence not marking a completion have no impact.
2407          api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_LOG, 'commentincontext', 'core');
2408          $uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get('id')));
2409          $this->assertSame(null, $uc1a->get('proficiency'));
2410          $this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?', array($u1->id, $c1->get('id'))));
2411  
2412          // Now let's try complete a competency but the rule won't match (not all children are complete).
2413          // The parent (the thing with the rule) will be created but won't have any evidence attached, and not
2414          // not be marked as completed.
2415          api::add_evidence($u1->id, $c1a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2416          $uc1a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1a->get('id')));
2417          $this->assertEquals(true, $uc1a->get('proficiency'));
2418          $uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2419          $this->assertSame(null, $uc1->get('proficiency'));
2420          $this->assertEquals(0, evidence::count_records(array('usercompetencyid' => $uc1->get('id'))));
2421  
2422          // Now we complete the other child. That will mark the parent as complete with an evidence.
2423          api::add_evidence($u1->id, $c1b, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2424          $uc1b = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1b->get('id')));
2425          $this->assertEquals(true, $uc1a->get('proficiency'));
2426          $uc1 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c1->get('id')));
2427          $this->assertEquals(true, $uc1->get('proficiency'));
2428          $this->assertEquals(user_competency::STATUS_IDLE, $uc1->get('status'));
2429          $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc1->get('id'))));
2430  
2431          // Check rule recommending.
2432          api::add_evidence($u1->id, $c2a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2433          $uc2a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2a->get('id')));
2434          $this->assertEquals(true, $uc1a->get('proficiency'));
2435          $uc2 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));
2436          $this->assertSame(null, $uc2->get('proficiency'));
2437          $this->assertEquals(user_competency::STATUS_WAITING_FOR_REVIEW, $uc2->get('status'));
2438          $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc2->get('id'))));
2439  
2440          // Check rule evidence.
2441          api::add_evidence($u1->id, $c3a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2442          $uc3a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3a->get('id')));
2443          $this->assertEquals(true, $uc1a->get('proficiency'));
2444          $uc3 = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get('id')));
2445          $this->assertSame(null, $uc3->get('proficiency'));
2446          $this->assertEquals(user_competency::STATUS_IDLE, $uc3->get('status'));
2447          $this->assertEquals(1, evidence::count_records(array('usercompetencyid' => $uc3->get('id'))));
2448  
2449          // Check rule nothing.
2450          api::add_evidence($u1->id, $c4a, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2451          $uc4a = user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4a->get('id')));
2452          $this->assertEquals(true, $uc1a->get('proficiency'));
2453          $this->assertFalse(user_competency::record_exists_select('userid = ? AND competencyid = ?', array($u1->id, $c4->get('id'))));
2454  
2455          // Check marking on something that has no parent. This just checks that nothing breaks.
2456          api::add_evidence($u1->id, $c5, $ctxid, evidence::ACTION_COMPLETE, 'commentincontext', 'core');
2457      }
2458  
2459      /**
2460       * Tests for the user_competency_course data when api::add_evidence() is invoked when
2461       * grading a user competency in the system context.
2462       */
2463      public function test_add_evidence_for_user_competency_course_grade_outside_course() {
2464          $this->resetAfterTest(true);
2465          $dg = $this->getDataGenerator();
2466          $syscontext = context_system::instance();
2467  
2468          // Create a student.
2469          $student = $dg->create_user();
2470  
2471          // Create a competency for the course.
2472          $lpg = $dg->get_plugin_generator('core_competency');
2473          $framework = $lpg->create_framework();
2474          $comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2475  
2476          // Add evidence.
2477          api::add_evidence($student->id, $comp, $syscontext, evidence::ACTION_OVERRIDE,
2478              'commentincontext', 'core', null, false, null, 1);
2479  
2480          // Query for user_competency_course data.
2481          $filterparams = array(
2482              'userid' => $student->id,
2483              'competencyid' => $comp->get('id'),
2484          );
2485          $usercompcourse = \core_competency\user_competency_course::get_record($filterparams);
2486          // There should be no user_competency_course object created when grading.
2487          $this->assertFalse($usercompcourse);
2488      }
2489  
2490      /**
2491       * Tests for the user_competency_course data when api::add_evidence() is invoked when
2492       * grading a user competency in a course.
2493       */
2494      public function test_add_evidence_user_competency_course_grade_in_course() {
2495          global $USER;
2496  
2497          $this->resetAfterTest(true);
2498          $dg = $this->getDataGenerator();
2499  
2500          // Create and assign a current user.
2501          $currentuser = $dg->create_user();
2502          $this->setUser($currentuser);
2503  
2504          // Create a course.
2505          $course = $dg->create_course();
2506          $record = array('courseid' => $course->id, 'pushratingstouserplans' => false);
2507          $settings = new course_competency_settings(0, (object) $record);
2508          $settings->create();
2509          $coursecontext = context_course::instance($course->id);
2510  
2511          // Create a student and enrol into the course.
2512          $student = $dg->create_user();
2513          $studentarch = get_archetype_roles('student');
2514          $studentrole = array_shift($studentarch);
2515          $dg->role_assign($studentrole->id, $student->id, $coursecontext->id);
2516          $dg->enrol_user($student->id, $course->id, $studentrole->id);
2517  
2518          // Create a competency for the course.
2519          $lpg = $dg->get_plugin_generator('core_competency');
2520          $framework = $lpg->create_framework();
2521          // Do not push ratings from course to user plans.
2522          $comp = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2523          $lpg->create_course_competency(array('courseid' => $course->id, 'competencyid' => $comp->get('id')));
2524  
2525          // Query for user_competency_course data.
2526          $filterparams = array(
2527              'userid' => $student->id,
2528              'competencyid' => $comp->get('id'),
2529              'courseid' => $course->id
2530          );
2531  
2532          // Add evidence that sets a grade to the course.
2533          $evidence = api::add_evidence($student->id, $comp, $coursecontext, evidence::ACTION_OVERRIDE,
2534              'commentincontext', 'core', null, false, null, 3, $USER->id);
2535          // Get user competency course record.
2536          $usercompcourse = \core_competency\user_competency_course::get_record($filterparams);
2537          // There should be a user_competency_course object when adding a grade.
2538          $this->assertNotEmpty($usercompcourse);
2539          $grade = $evidence->get('grade');
2540          $this->assertEquals($grade, $usercompcourse->get('grade'));
2541          $this->assertEquals(3, $usercompcourse->get('grade'));
2542          $proficiency = $comp->get_proficiency_of_grade($grade);
2543          $this->assertEquals($proficiency, $usercompcourse->get('proficiency'));
2544  
2545          // Confirm that the user competency's grade/proficiency has not been affected by the grade.
2546          $usercompetencyparams = [
2547              'userid' => $student->id,
2548              'competencyid' => $comp->get('id'),
2549          ];
2550          $usercompetency = \core_competency\user_competency::get_record($usercompetencyparams);
2551          $this->assertNotEmpty($usercompetency);
2552          $this->assertNotEquals($usercompcourse->get('grade'), $usercompetency->get('grade'));
2553          $this->assertNotEquals($usercompcourse->get('proficiency'), $usercompetency->get('proficiency'));
2554      }
2555  
2556      public function test_observe_course_completed() {
2557          $this->resetAfterTest(true);
2558          $dg = $this->getDataGenerator();
2559          $lpg = $dg->get_plugin_generator('core_competency');
2560  
2561          // Set-up users, framework, competencies and course competencies.
2562          $course = $dg->create_course();
2563          $coursectx = context_course::instance($course->id);
2564          $u1 = $dg->create_user();
2565          $f1 = $lpg->create_framework();
2566          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2567          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2568          $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2569          $c4 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
2570          $cc1 = $lpg->create_course_competency(array('competencyid' => $c1->get('id'), 'courseid' => $course->id,
2571              'ruleoutcome' => \core_competency\course_competency::OUTCOME_NONE));
2572          $cc2 = $lpg->create_course_competency(array('competencyid' => $c2->get('id'), 'courseid' => $course->id,
2573              'ruleoutcome' => \core_competency\course_competency::OUTCOME_EVIDENCE));
2574          $cc3 = $lpg->create_course_competency(array('competencyid' => $c3->get('id'), 'courseid' => $course->id,
2575              'ruleoutcome' => \core_competency\course_competency::OUTCOME_RECOMMEND));
2576          $cc4 = $lpg->create_course_competency(array('competencyid' => $c4->get('id'), 'courseid' => $course->id,
2577              'ruleoutcome' => \core_competency\course_competency::OUTCOME_COMPLETE));
2578  
2579          $event = \core\event\course_completed::create(array(
2580              'objectid' => 1,
2581              'relateduserid' => $u1->id,
2582              'context' => $coursectx,
2583              'courseid' => $course->id,
2584              'other' => array('relateduserid' => $u1->id)
2585          ));
2586          $this->assertEquals(0, \core_competency\user_competency::count_records());
2587          $this->assertEquals(0, \core_competency\evidence::count_records());
2588  
2589          // Let's go!
2590          api::observe_course_completed($event);
2591          $this->assertEquals(3, \core_competency\user_competency::count_records());
2592          $this->assertEquals(3, \core_competency\evidence::count_records());
2593  
2594          // Outcome NONE did nothing.
2595          $this->assertFalse(\core_competency\user_competency::record_exists_select('userid = :uid AND competencyid = :cid', array(
2596              'uid' => $u1->id, 'cid' => $c1->get('id')
2597          )));
2598  
2599          // Outcome evidence.
2600          $uc2 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c2->get('id')));
2601          $ev2 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc2->get('id')));
2602  
2603          $this->assertEquals(null, $uc2->get('grade'));
2604          $this->assertEquals(null, $uc2->get('proficiency'));
2605          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc2->get('status'));
2606  
2607          $this->assertEquals('evidence_coursecompleted', $ev2->get('descidentifier'));
2608          $this->assertEquals('core_competency', $ev2->get('desccomponent'));
2609          $this->assertEquals($course->shortname, $ev2->get('desca'));
2610          $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev2->get('url'));
2611          $this->assertEquals(null, $ev2->get('grade'));
2612          $this->assertEquals($coursectx->id, $ev2->get('contextid'));
2613          $this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev2->get('action'));
2614          $this->assertEquals(null, $ev2->get('actionuserid'));
2615  
2616          // Outcome recommend.
2617          $uc3 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c3->get('id')));
2618          $ev3 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc3->get('id')));
2619  
2620          $this->assertEquals(null, $uc3->get('grade'));
2621          $this->assertEquals(null, $uc3->get('proficiency'));
2622          $this->assertEquals(\core_competency\user_competency::STATUS_WAITING_FOR_REVIEW, $uc3->get('status'));
2623  
2624          $this->assertEquals('evidence_coursecompleted', $ev3->get('descidentifier'));
2625          $this->assertEquals('core_competency', $ev3->get('desccomponent'));
2626          $this->assertEquals($course->shortname, $ev3->get('desca'));
2627          $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev3->get('url'));
2628          $this->assertEquals(null, $ev3->get('grade'));
2629          $this->assertEquals($coursectx->id, $ev3->get('contextid'));
2630          $this->assertEquals(\core_competency\evidence::ACTION_LOG, $ev3->get('action'));
2631          $this->assertEquals(null, $ev3->get('actionuserid'));
2632  
2633          // Outcome complete.
2634          $uc4 = \core_competency\user_competency::get_record(array('userid' => $u1->id, 'competencyid' => $c4->get('id')));
2635          $ev4 = \core_competency\evidence::get_record(array('usercompetencyid' => $uc4->get('id')));
2636  
2637          $this->assertEquals(3, $uc4->get('grade'));
2638          $this->assertEquals(1, $uc4->get('proficiency'));
2639          $this->assertEquals(\core_competency\user_competency::STATUS_IDLE, $uc4->get('status'));
2640  
2641          $this->assertEquals('evidence_coursecompleted', $ev4->get('descidentifier'));
2642          $this->assertEquals('core_competency', $ev4->get('desccomponent'));
2643          $this->assertEquals($course->shortname, $ev4->get('desca'));
2644          $this->assertStringEndsWith('/report/completion/index.php?course=' . $course->id, $ev4->get('url'));
2645          $this->assertEquals(3, $ev4->get('grade'));
2646          $this->assertEquals($coursectx->id, $ev4->get('contextid'));
2647          $this->assertEquals(\core_competency\evidence::ACTION_COMPLETE, $ev4->get('action'));
2648          $this->assertEquals(null, $ev4->get('actionuserid'));
2649      }
2650  
2651      public function test_list_evidence_in_course() {
2652          global $SITE;
2653  
2654          $this->resetAfterTest(true);
2655          $dg = $this->getDataGenerator();
2656          $lpg = $dg->get_plugin_generator('core_competency');
2657          $u1 = $dg->create_user();
2658          $course = $dg->create_course();
2659          $coursecontext = context_course::instance($course->id);
2660  
2661          $this->setAdminUser();
2662          $f = $lpg->create_framework();
2663          $c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
2664          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
2665          $cc = api::add_competency_to_course($course->id, $c->get('id'));
2666          $cc2 = api::add_competency_to_course($course->id, $c2->get('id'));
2667  
2668          $pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');
2669          $page = $pagegenerator->create_instance(array('course' => $course->id));
2670  
2671          $cm = get_coursemodule_from_instance('page', $page->id);
2672          $cmcontext = context_module::instance($cm->id);
2673          // Add the competency to the course module.
2674          $ccm = api::add_competency_to_course_module($cm, $c->get('id'));
2675  
2676          // Now add the evidence to the course.
2677          $evidence1 = api::add_evidence($u1->id, $c->get('id'), $coursecontext->id, \core_competency\evidence::ACTION_LOG,
2678              'invaliddata', 'error');
2679  
2680          $result = api::list_evidence_in_course($u1->id, $course->id, $c->get('id'));
2681          $this->assertEquals($result[0]->get('id'), $evidence1->get('id'));
2682  
2683          // Now add the evidence to the course module.
2684          $evidence2 = api::add_evidence($u1->id, $c->get('id'), $cmcontext->id, \core_competency\evidence::ACTION_LOG,
2685              'invaliddata', 'error');
2686  
2687          $result = api::list_evidence_in_course($u1->id, $course->id, $c->get('id'), 'timecreated', 'ASC');
2688          $this->assertEquals($evidence1->get('id'), $result[0]->get('id'));
2689          $this->assertEquals($evidence2->get('id'), $result[1]->get('id'));
2690      }
2691  
2692      public function test_list_course_modules_using_competency() {
2693          global $SITE;
2694  
2695          $this->resetAfterTest(true);
2696          $dg = $this->getDataGenerator();
2697          $lpg = $dg->get_plugin_generator('core_competency');
2698          $u1 = $dg->create_user();
2699          $u2 = $dg->create_user();
2700          $course = $dg->create_course();
2701          $course2 = $dg->create_course();
2702  
2703          $this->setAdminUser();
2704          $f = $lpg->create_framework();
2705          $c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
2706          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
2707          $cc = api::add_competency_to_course($course->id, $c->get('id'));
2708          $cc2 = api::add_competency_to_course($course->id, $c2->get('id'));
2709  
2710          // First check we get an empty list when there are no links.
2711          $expected = array();
2712          $result = api::list_course_modules_using_competency($c->get('id'), $course->id);
2713          $this->assertEquals($expected, $result);
2714  
2715          $pagegenerator = $this->getDataGenerator()->get_plugin_generator('mod_page');
2716          $page = $pagegenerator->create_instance(array('course' => $course->id));
2717  
2718          $cm = get_coursemodule_from_instance('page', $page->id);
2719          // Add a link and list again.
2720          $ccm = api::add_competency_to_course_module($cm, $c->get('id'));
2721          $expected = array($cm->id);
2722          $result = api::list_course_modules_using_competency($c->get('id'), $course->id);
2723          $this->assertEquals($expected, $result);
2724  
2725          // Check a different course.
2726          $expected = array();
2727          $result = api::list_course_modules_using_competency($c->get('id'), $course2->id);
2728          $this->assertEquals($expected, $result);
2729  
2730          // Remove the link and check again.
2731          $result = api::remove_competency_from_course_module($cm, $c->get('id'));
2732          $expected = true;
2733          $this->assertEquals($expected, $result);
2734          $expected = array();
2735          $result = api::list_course_modules_using_competency($c->get('id'), $course->id);
2736          $this->assertEquals($expected, $result);
2737  
2738          // Now add 2 links.
2739          api::add_competency_to_course_module($cm, $c->get('id'));
2740          api::add_competency_to_course_module($cm, $c2->get('id'));
2741          $result = api::list_course_module_competencies_in_course_module($cm->id);
2742          $this->assertEquals($result[0]->get('competencyid'), $c->get('id'));
2743          $this->assertEquals($result[1]->get('competencyid'), $c2->get('id'));
2744  
2745          // Now re-order.
2746          api::reorder_course_module_competency($cm, $c->get('id'), $c2->get('id'));
2747          $result = api::list_course_module_competencies_in_course_module($cm->id);
2748          $this->assertEquals($result[0]->get('competencyid'), $c2->get('id'));
2749          $this->assertEquals($result[1]->get('competencyid'), $c->get('id'));
2750  
2751          // And re-order again.
2752          api::reorder_course_module_competency($cm, $c->get('id'), $c2->get('id'));
2753          $result = api::list_course_module_competencies_in_course_module($cm->id);
2754          $this->assertEquals($result[0]->get('competencyid'), $c->get('id'));
2755          $this->assertEquals($result[1]->get('competencyid'), $c2->get('id'));
2756  
2757          // Now get the course competency and coursemodule competency together.
2758          $result = api::list_course_module_competencies($cm->id);
2759          // Now we should have an array and each element of the array should have a competency and
2760          // a coursemodulecompetency.
2761          foreach ($result as $instance) {
2762              $cmc = $instance['coursemodulecompetency'];
2763              $c = $instance['competency'];
2764              $this->assertEquals($cmc->get('competencyid'), $c->get('id'));
2765          }
2766      }
2767  
2768      /**
2769       * Test update ruleoutcome for course_competency.
2770       */
2771      public function test_set_ruleoutcome_course_competency() {
2772          $this->resetAfterTest(true);
2773          $dg = $this->getDataGenerator();
2774          $lpg = $dg->get_plugin_generator('core_competency');
2775          $u1 = $dg->create_user();
2776          $u2 = $dg->create_user();
2777          $course = $dg->create_course();
2778  
2779          $this->setAdminUser();
2780          $f = $lpg->create_framework();
2781          $c = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
2782          $cc = api::add_competency_to_course($course->id, $c->get('id'));
2783  
2784          // Check record was created with default rule value Evidence.
2785          $this->assertEquals(1, \core_competency\course_competency::count_records());
2786          $recordscc = api::list_course_competencies($course->id);
2787          $this->assertEquals(\core_competency\course_competency::OUTCOME_EVIDENCE,
2788              $recordscc[0]['coursecompetency']->get('ruleoutcome'));
2789  
2790          // Check ruleoutcome value is updated to None.
2791          $this->assertTrue(api::set_course_competency_ruleoutcome($recordscc[0]['coursecompetency']->get('id'),
2792              \core_competency\course_competency::OUTCOME_NONE));
2793          $recordscc = api::list_course_competencies($course->id);
2794          $this->assertEquals(\core_competency\course_competency::OUTCOME_NONE, $recordscc[0]['coursecompetency']->get('ruleoutcome'));
2795      }
2796  
2797      /**
2798       * Test validation on grade on user_competency.
2799       */
2800      public function test_validate_grade_in_user_competency() {
2801          global $DB;
2802  
2803          $this->resetAfterTest(true);
2804          $this->setAdminUser();
2805          $dg = $this->getDataGenerator();
2806          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2807          $user = $dg->create_user();
2808  
2809          $s1 = $dg->create_scale(array("scale" => "value1, value2"));
2810          $s2 = $dg->create_scale(array("scale" => "value3, value4, value5, value6"));
2811  
2812          $scaleconfiguration1 = '[{"scaleid":"'.$s1->id.'"},{"name":"value1","id":1,"scaledefault":1,"proficient":0},' .
2813                  '{"name":"value2","id":2,"scaledefault":0,"proficient":1}]';
2814          $scaleconfiguration2 = '[{"scaleid":"'.$s2->id.'"},{"name":"value3","id":1,"scaledefault":1,"proficient":0},'
2815                  . '{"name":"value4","id":2,"scaledefault":0,"proficient":1}]';
2816  
2817          // Create a framework with scale configuration1.
2818          $frm = array(
2819              'scaleid' => $s1->id,
2820              'scaleconfiguration' => $scaleconfiguration1
2821          );
2822          $framework = $lpg->create_framework($frm);
2823          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2824  
2825          // Create competency with its own scale configuration.
2826          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id'),
2827                                              'scaleid' => $s2->id,
2828                                              'scaleconfiguration' => $scaleconfiguration2
2829                                          ));
2830  
2831          // Detecte invalid grade in competency using its framework competency scale.
2832          try {
2833              $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get('id'),
2834                  'proficiency' => true, 'grade' => 3 ));
2835              $usercompetency->create();
2836              $this->fail('Invalid grade not detected in framework scale');
2837          } catch (\core\invalid_persistent_exception $e) {
2838              $this->assertTrue(true);
2839          }
2840  
2841          // Detecte invalid grade in competency using its own scale.
2842          try {
2843              $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get('id'),
2844                  'proficiency' => true, 'grade' => 5 ));
2845              $usercompetency->create();
2846              $this->fail('Invalid grade not detected in competency scale');
2847          } catch (\core\invalid_persistent_exception $e) {
2848              $this->assertTrue(true);
2849          }
2850  
2851          // Accept valid grade in competency using its framework competency scale.
2852          try {
2853              $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c1->get('id'),
2854                  'proficiency' => true, 'grade' => 1 ));
2855              $usercompetency->create();
2856              $this->assertTrue(true);
2857          } catch (\core\invalid_persistent_exception $e) {
2858              $this->fail('Valide grade rejected in framework scale');
2859          }
2860  
2861          // Accept valid grade in competency using its framework competency scale.
2862          try {
2863              $usercompetency = new user_competency(0, (object) array('userid' => $user->id, 'competencyid' => $c2->get('id'),
2864                  'proficiency' => true, 'grade' => 4 ));
2865              $usercompetency->create();
2866              $this->assertTrue(true);
2867          } catch (\core\invalid_persistent_exception $e) {
2868              $this->fail('Valide grade rejected in competency scale');
2869          }
2870      }
2871  
2872      /**
2873       * Test when adding competency that belong to hidden framework to plan/template/course.
2874       */
2875      public function test_hidden_framework() {
2876          $this->resetAfterTest(true);
2877          $this->setAdminUser();
2878          $dg = $this->getDataGenerator();
2879          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2880          $user = $dg->create_user();
2881  
2882          // Create a course.
2883          $cat1 = $dg->create_category();
2884          $course = $dg->create_course(array('category' => $cat1->id));
2885          // Create a template.
2886          $template = $lpg->create_template();
2887          // Create a plan.
2888          $plan = $lpg->create_plan(array('userid' => $user->id));
2889  
2890          // Create a hidden framework.
2891          $frm = array(
2892              'visible' => false
2893          );
2894          $framework = $lpg->create_framework($frm);
2895          $competency = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2896  
2897          // Linking competency that belong to hidden framework to course.
2898          try {
2899              api::add_competency_to_course($course->id, $competency->get('id'));
2900              $this->fail('A competency belonging to hidden framework can not be linked to course');
2901          } catch (coding_exception $e) {
2902              $this->assertTrue(true);
2903          }
2904  
2905          // Adding competency that belong to hidden framework to template.
2906          try {
2907              api::add_competency_to_template($template->get('id'), $competency->get('id'));
2908              $this->fail('A competency belonging to hidden framework can not be added to template');
2909          } catch (coding_exception $e) {
2910              $this->assertTrue(true);
2911          }
2912  
2913          // Adding competency that belong to hidden framework to plan.
2914          try {
2915              api::add_competency_to_plan($plan->get('id'), $competency->get('id'));
2916              $this->fail('A competency belonging to hidden framework can not be added to plan');
2917          } catch (coding_exception $e) {
2918              $this->assertTrue(true);
2919          }
2920      }
2921  
2922      /**
2923       * Test when using hidden template in plan/cohort.
2924       */
2925      public function test_hidden_template() {
2926          $this->resetAfterTest(true);
2927          $this->setAdminUser();
2928          $dg = $this->getDataGenerator();
2929          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2930          $user = $dg->create_user();
2931  
2932          // Create a cohort.
2933          $cohort = $dg->create_cohort();
2934          // Create a hidden template.
2935          $template = $lpg->create_template(array('visible' => false));
2936  
2937          // Can not link hidden template to plan.
2938          try {
2939              api::create_plan_from_template($template->get('id'), $user->id);
2940              $this->fail('Can not link a hidden template to plan');
2941          } catch (coding_exception $e) {
2942              $this->assertTrue(true);
2943          }
2944  
2945          // Can associate hidden template to cohort.
2946          $templatecohort = api::create_template_cohort($template->get('id'), $cohort->id);
2947          $this->assertInstanceOf('\core_competency\template_cohort', $templatecohort);
2948      }
2949  
2950      /**
2951       * Test that completed plan created form a template does not change when template is modified.
2952       */
2953      public function test_completed_plan_doesnot_change() {
2954          global $DB;
2955  
2956          $this->resetAfterTest(true);
2957          $this->setAdminUser();
2958          $dg = $this->getDataGenerator();
2959          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2960          $user = $dg->create_user();
2961  
2962          // Create a framework and assign competencies.
2963          $framework = $lpg->create_framework();
2964          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2965          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2966          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2967          $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2968  
2969          // Create template and assign competencies.
2970          $tp = $lpg->create_template();
2971          $tpc1 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c1->get('id')));
2972          $tpc2 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c2->get('id')));
2973          $tpc3 = $lpg->create_template_competency(array('templateid' => $tp->get('id'), 'competencyid' => $c3->get('id')));
2974  
2975          // Create a plan form template and change it status to complete.
2976          $plan = $lpg->create_plan(array('userid' => $user->id, 'templateid' => $tp->get('id')));
2977          api::complete_plan($plan);
2978  
2979          // Check user competency plan created correctly.
2980          $this->assertEquals(3, \core_competency\user_competency_plan::count_records());
2981          $ucp = \core_competency\user_competency_plan::get_records();
2982          $this->assertEquals($ucp[0]->get('competencyid'), $c1->get('id'));
2983          $this->assertEquals($ucp[1]->get('competencyid'), $c2->get('id'));
2984          $this->assertEquals($ucp[2]->get('competencyid'), $c3->get('id'));
2985  
2986          // Add and remove a competency from the template.
2987          api::add_competency_to_template($tp->get('id'), $c4->get('id'));
2988          api::remove_competency_from_template($tp->get('id'), $c1->get('id'));
2989  
2990          // Check that user competency plan did not change.
2991          $competencies = $plan->get_competencies();
2992          $this->assertEquals(3, count($competencies));
2993          $ucp1 = array($c1->get('id'), $c2->get('id'), $c3->get('id'));
2994          $ucp2 = array();
2995          foreach ($competencies as $id => $cmp) {
2996              $ucp2[] = $id;
2997          }
2998          $this->assertEquals(0, count(array_diff($ucp1, $ucp2)));
2999      }
3000  
3001      protected function setup_framework_for_reset_rules_tests() {
3002          $this->resetAfterTest(true);
3003          $dg = $this->getDataGenerator();
3004          $lpg = $dg->get_plugin_generator('core_competency');
3005  
3006          $this->setAdminUser();
3007          $f1 = $lpg->create_framework();
3008          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3009          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3010          $c1a1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3011          $c1a1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a1->get('id')));
3012          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3013          $c1b1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3014          $c1b1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b1->get('id')));
3015          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3016          $c2a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3017  
3018          $c1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3019          $c1->set('ruletype', 'core_competency\\competency_rule_all');
3020          $c1->update();
3021          $c1a->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3022          $c1a->set('ruletype', 'core_competency\\competency_rule_all');
3023          $c1a->update();
3024          $c1a1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3025          $c1a1->set('ruletype', 'core_competency\\competency_rule_all');
3026          $c1a1->update();
3027          $c1b->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3028          $c1b->set('ruletype', 'core_competency\\competency_rule_all');
3029          $c1b->update();
3030          $c2->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3031          $c2->set('ruletype', 'core_competency\\competency_rule_all');
3032          $c2->update();
3033  
3034          return array(
3035              'f1' => $f1,
3036              'c1' => $c1,
3037              'c1a' => $c1a,
3038              'c1a1' => $c1a1,
3039              'c1a1a' => $c1a1a,
3040              'c1b' => $c1b,
3041              'c1b1' => $c1b1,
3042              'c1b1a' => $c1b1a,
3043              'c2' => $c2,
3044              'c2a' => $c2a,
3045          );
3046      }
3047  
3048      public function test_moving_competency_reset_rules_updown() {
3049          $data = $this->setup_framework_for_reset_rules_tests();
3050          $f1 = $data['f1'];
3051          $c1 = $data['c1'];
3052          $c1a = $data['c1a'];
3053          $c1a1 = $data['c1a1'];
3054          $c1a1a = $data['c1a1a'];
3055          $c1b = $data['c1b'];
3056          $c1b1 = $data['c1b1'];
3057          $c1b1a = $data['c1b1a'];
3058          $c2 = $data['c2'];
3059          $c2a = $data['c2a'];
3060  
3061          // Moving up and down doesn't change anything.
3062          api::move_down_competency($c1a->get('id'));
3063          $c1->read();
3064          $c1a->read();
3065          $c1a1->read();
3066          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));
3067          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));
3068          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));
3069          api::move_up_competency($c1a->get('id'));
3070          $c1->read();
3071          $c1a->read();
3072          $c1a1->read();
3073          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));
3074          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));
3075          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));
3076      }
3077  
3078      public function test_moving_competency_reset_rules_parent() {
3079          $data = $this->setup_framework_for_reset_rules_tests();
3080          $f1 = $data['f1'];
3081          $c1 = $data['c1'];
3082          $c1a = $data['c1a'];
3083          $c1a1 = $data['c1a1'];
3084          $c1a1a = $data['c1a1a'];
3085          $c1b = $data['c1b'];
3086          $c1b1 = $data['c1b1'];
3087          $c1b1a = $data['c1b1a'];
3088          $c2 = $data['c2'];
3089          $c2a = $data['c2a'];
3090  
3091          // Moving out of parent will reset the parent, and the destination.
3092          api::set_parent_competency($c1a->get('id'), $c1b->get('id'));
3093          $c1->read();
3094          $c1a->read();
3095          $c1a1->read();
3096          $c1b->read();
3097          $c2->read();
3098          $this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));
3099          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));
3100          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));
3101          $this->assertEquals(competency::OUTCOME_NONE, $c1b->get('ruleoutcome'));
3102          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3103      }
3104  
3105      public function test_moving_competency_reset_rules_totoplevel() {
3106          $data = $this->setup_framework_for_reset_rules_tests();
3107          $f1 = $data['f1'];
3108          $c1 = $data['c1'];
3109          $c1a = $data['c1a'];
3110          $c1a1 = $data['c1a1'];
3111          $c1a1a = $data['c1a1a'];
3112          $c1b = $data['c1b'];
3113          $c1b1 = $data['c1b1'];
3114          $c1b1a = $data['c1b1a'];
3115          $c2 = $data['c2'];
3116          $c2a = $data['c2a'];
3117  
3118          // Moving to top level only affects the initial parent.
3119          api::set_parent_competency($c1a1->get('id'), 0);
3120          $c1->read();
3121          $c1a->read();
3122          $c1a1->read();
3123          $c1b->read();
3124          $c2->read();
3125          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));
3126          $this->assertEquals(competency::OUTCOME_NONE, $c1a->get('ruleoutcome'));
3127          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));
3128          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));
3129          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3130      }
3131  
3132      public function test_moving_competency_reset_rules_fromtoplevel() {
3133          $data = $this->setup_framework_for_reset_rules_tests();
3134          $f1 = $data['f1'];
3135          $c1 = $data['c1'];
3136          $c1a = $data['c1a'];
3137          $c1a1 = $data['c1a1'];
3138          $c1a1a = $data['c1a1a'];
3139          $c1b = $data['c1b'];
3140          $c1b1 = $data['c1b1'];
3141          $c1b1a = $data['c1b1a'];
3142          $c2 = $data['c2'];
3143          $c2a = $data['c2a'];
3144  
3145          // Moving from top level only affects the destination parent.
3146          api::set_parent_competency($c2->get('id'), $c1a1->get('id'));
3147          $c1->read();
3148          $c1a->read();
3149          $c1a1->read();
3150          $c1b->read();
3151          $c2->read();
3152          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1->get('ruleoutcome'));
3153          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));
3154          $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get('ruleoutcome'));
3155          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));
3156          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3157      }
3158  
3159      public function test_moving_competency_reset_rules_child() {
3160          $data = $this->setup_framework_for_reset_rules_tests();
3161          $f1 = $data['f1'];
3162          $c1 = $data['c1'];
3163          $c1a = $data['c1a'];
3164          $c1a1 = $data['c1a1'];
3165          $c1a1a = $data['c1a1a'];
3166          $c1b = $data['c1b'];
3167          $c1b1 = $data['c1b1'];
3168          $c1b1a = $data['c1b1a'];
3169          $c2 = $data['c2'];
3170          $c2a = $data['c2a'];
3171  
3172          // Moving to a child of self resets self, parent and destination.
3173          api::set_parent_competency($c1a->get('id'), $c1a1->get('id'));
3174          $c1->read();
3175          $c1a->read();
3176          $c1a1->read();
3177          $c1b->read();
3178          $c2->read();
3179          $this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));
3180          $this->assertEquals(competency::OUTCOME_NONE, $c1a->get('ruleoutcome'));
3181          $this->assertEquals(competency::OUTCOME_NONE, $c1a1->get('ruleoutcome'));
3182          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));
3183          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3184      }
3185  
3186      public function test_create_competency_reset_rules() {
3187          $data = $this->setup_framework_for_reset_rules_tests();
3188          $f1 = $data['f1'];
3189          $c1 = $data['c1'];
3190          $c1a = $data['c1a'];
3191          $c1a1 = $data['c1a1'];
3192          $c1a1a = $data['c1a1a'];
3193          $c1b = $data['c1b'];
3194          $c1b1 = $data['c1b1'];
3195          $c1b1a = $data['c1b1a'];
3196          $c2 = $data['c2'];
3197          $c2a = $data['c2a'];
3198  
3199          // Adding a new competency resets the rule of its parent.
3200          api::create_competency((object) array('shortname' => 'A', 'parentid' => $c1->get('id'), 'idnumber' => 'A',
3201              'competencyframeworkid' => $f1->get('id')));
3202          $c1->read();
3203          $c1a->read();
3204          $c1a1->read();
3205          $c1b->read();
3206          $c2->read();
3207          $this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));
3208          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a->get('ruleoutcome'));
3209          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1a1->get('ruleoutcome'));
3210          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));
3211          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3212      }
3213  
3214      public function test_delete_competency_reset_rules() {
3215          $data = $this->setup_framework_for_reset_rules_tests();
3216          $f1 = $data['f1'];
3217          $c1 = $data['c1'];
3218          $c1a = $data['c1a'];
3219          $c1a1 = $data['c1a1'];
3220          $c1a1a = $data['c1a1a'];
3221          $c1b = $data['c1b'];
3222          $c1b1 = $data['c1b1'];
3223          $c1b1a = $data['c1b1a'];
3224          $c2 = $data['c2'];
3225          $c2a = $data['c2a'];
3226  
3227          // Deleting a competency resets the rule of its parent.
3228          api::delete_competency($c1a->get('id'));
3229          $c1->read();
3230          $c1b->read();
3231          $c2->read();
3232          $this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));
3233          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c1b->get('ruleoutcome'));
3234          $this->assertEquals(competency::OUTCOME_EVIDENCE, $c2->get('ruleoutcome'));
3235      }
3236  
3237      public function test_template_has_related_data() {
3238          $this->resetAfterTest(true);
3239          $this->setAdminUser();
3240  
3241          $dg = $this->getDataGenerator();
3242          $user = $dg->create_user();
3243          $lpg = $dg->get_plugin_generator('core_competency');
3244          $tpl1 = $lpg->create_template();
3245          $tpl2 = $lpg->create_template();
3246  
3247          // Create plans for first template.
3248          $time = time();
3249          $plan1 = $lpg->create_plan(array('templateid' => $tpl1->get('id'), 'userid' => $user->id,
3250              'name' => 'Not good name', 'duedate' => $time + 3600, 'description' => 'Ahah', 'descriptionformat' => FORMAT_PLAIN));
3251  
3252          $this->assertTrue(api::template_has_related_data($tpl1->get('id')));
3253          $this->assertFalse(api::template_has_related_data($tpl2->get('id')));
3254  
3255      }
3256  
3257      public function test_delete_template_delete_plans() {
3258          $this->resetAfterTest(true);
3259          $this->setAdminUser();
3260  
3261          $dg = $this->getDataGenerator();
3262          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
3263  
3264          $u1 = $dg->create_user();
3265          $f = $lpg->create_framework();
3266          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
3267          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
3268  
3269          $tpl = $lpg->create_template();
3270  
3271          $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1->get('id'),
3272              'sortorder' => 1));
3273          $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c2->get('id'),
3274              'sortorder' => 2));
3275  
3276          $p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));
3277  
3278          // Check pre-test.
3279          $this->assertTrue(\core_competency\template::record_exists($tpl->get('id')));
3280          $this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get('id')));
3281          $this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));
3282  
3283          $result = api::delete_template($tpl->get('id'), true);
3284          $this->assertTrue($result);
3285  
3286          // Check that the template does not exist anymore.
3287          $this->assertFalse(\core_competency\template::record_exists($tpl->get('id')));
3288  
3289          // Check that associated competencies are also deleted.
3290          $this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get('id')));
3291  
3292          // Check that associated plan are also deleted.
3293          $this->assertEquals(0, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));
3294      }
3295  
3296      public function test_delete_template_unlink_plans() {
3297          $this->resetAfterTest(true);
3298          $this->setAdminUser();
3299  
3300          $dg = $this->getDataGenerator();
3301          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
3302  
3303          $u1 = $dg->create_user();
3304          $f = $lpg->create_framework();
3305          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
3306          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get('id')));
3307  
3308          $tpl = $lpg->create_template();
3309  
3310          $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1->get('id'),
3311              'sortorder' => 1));
3312          $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c2->get('id'),
3313              'sortorder' => 2));
3314  
3315          $p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));
3316  
3317          // Check pre-test.
3318          $this->assertTrue(\core_competency\template::record_exists($tpl->get('id')));
3319          $this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get('id')));
3320          $this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get('id')))));
3321  
3322          $result = api::delete_template($tpl->get('id'), false);
3323          $this->assertTrue($result);
3324  
3325          // Check that the template does not exist anymore.
3326          $this->assertFalse(\core_competency\template::record_exists($tpl->get('id')));
3327  
3328          // Check that associated competencies are also deleted.
3329          $this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get('id')));
3330  
3331          // Check that associated plan still exist but unlink from template.
3332          $plans = \core_competency\plan::get_records(array('id' => $p1->get('id')));
3333          $this->assertEquals(1, count($plans));
3334          $this->assertEquals($plans[0]->get('origtemplateid'), $tpl->get('id'));
3335          $this->assertNull($plans[0]->get('templateid'));
3336      }
3337  
3338      public function test_delete_competency() {
3339          $this->resetAfterTest(true);
3340          $dg = $this->getDataGenerator();
3341          $lpg = $dg->get_plugin_generator('core_competency');
3342          $this->setAdminUser();
3343  
3344          $u1 = $dg->create_user();
3345  
3346          $f1 = $lpg->create_framework();
3347          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3348          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3349          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3350          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3351          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3352          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3353  
3354          // Set rules on parent competency.
3355          $c1->set('ruleoutcome', competency::OUTCOME_EVIDENCE);
3356          $c1->set('ruletype', 'core_competency\\competency_rule_all');
3357          $c1->update();
3358  
3359          // If we delete competeny, the related competencies relations and evidences should be deleted.
3360          // Create related competencies using one of c1a competency descendants.
3361          $rc = $lpg->create_related_competency(array(
3362              'competencyid' => $c2->get('id'),
3363              'relatedcompetencyid' => $c11b->get('id')
3364          ));
3365          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3366  
3367          // Creating a standard evidence with minimal information.
3368          $uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3369          $evidence = $lpg->create_evidence(array('usercompetencyid' => $uc2->get('id')));
3370          $this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));
3371          $uc2->delete();
3372  
3373          $this->assertTrue(api::delete_competency($c1a->get('id')));
3374          $this->assertFalse(competency::record_exists($c1a->get('id')));
3375  
3376          // Check that on delete, we reset the rule on parent competency.
3377          $c1->read();
3378          $this->assertNull($c1->get('ruletype'));
3379          $this->assertNull($c1->get('ruletype'));
3380          $this->assertEquals(competency::OUTCOME_NONE, $c1->get('ruleoutcome'));
3381  
3382          // Check that descendants were also deleted.
3383          $this->assertFalse(competency::record_exists($c1b->get('id')));
3384          $this->assertFalse(competency::record_exists($c11b->get('id')));
3385          $this->assertFalse(competency::record_exists($c12b->get('id')));
3386  
3387          // Check if evidence are also deleted.
3388          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3389  
3390          // Check if related conpetency relation is deleted.
3391          $this->assertEquals(0, count(api::list_related_competencies($c2->get('id'))));
3392  
3393          // Delete a simple competency.
3394          $this->assertTrue(api::delete_competency($c2->get('id')));
3395          $this->assertFalse(competency::record_exists($c2->get('id')));
3396      }
3397  
3398      public function test_delete_competency_used_in_plan() {
3399          $this->resetAfterTest(true);
3400          $dg = $this->getDataGenerator();
3401          $lpg = $dg->get_plugin_generator('core_competency');
3402          $this->setAdminUser();
3403  
3404          $u1 = $dg->create_user();
3405  
3406          $plan = $lpg->create_plan((object) array('userid' => $u1->id));
3407  
3408          $f1 = $lpg->create_framework();
3409          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3410          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3411          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3412          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3413          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3414          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3415  
3416          // Add competency to plan.
3417          $pc = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c11b->get('id')));
3418          // We can not delete a competency , if competency or competency children is associated to plan.
3419          $this->assertFalse(api::delete_competency($c1a->get('id')));
3420  
3421          // We can delete the competency if we remove the competency from the plan.
3422          $pc->delete();
3423  
3424          $this->assertTrue(api::delete_competency($c1a->get('id')));
3425          $this->assertFalse(competency::record_exists($c1a->get('id')));
3426          $this->assertFalse(competency::record_exists($c1b->get('id')));
3427          $this->assertFalse(competency::record_exists($c11b->get('id')));
3428          $this->assertFalse(competency::record_exists($c12b->get('id')));
3429      }
3430  
3431      public function test_delete_competency_used_in_usercompetency() {
3432          $this->resetAfterTest(true);
3433          $dg = $this->getDataGenerator();
3434          $lpg = $dg->get_plugin_generator('core_competency');
3435          $this->setAdminUser();
3436  
3437          $u1 = $dg->create_user();
3438  
3439          $f1 = $lpg->create_framework();
3440          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3441          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3442          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3443          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3444          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3445          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3446  
3447          // Create user competency.
3448          $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3449  
3450          // We can not delete a competency , if competency or competency children exist in user competency.
3451          $this->assertFalse(api::delete_competency($c1a->get('id')));
3452  
3453          // We can delete the competency if we remove the competency from user competency.
3454          $uc1->delete();
3455  
3456          $this->assertTrue(api::delete_competency($c1a->get('id')));
3457          $this->assertFalse(competency::record_exists($c1a->get('id')));
3458          $this->assertFalse(competency::record_exists($c1b->get('id')));
3459          $this->assertFalse(competency::record_exists($c11b->get('id')));
3460          $this->assertFalse(competency::record_exists($c12b->get('id')));
3461      }
3462  
3463      public function test_delete_competency_used_in_usercompetencyplan() {
3464          $this->resetAfterTest(true);
3465          $dg = $this->getDataGenerator();
3466          $lpg = $dg->get_plugin_generator('core_competency');
3467          $this->setAdminUser();
3468  
3469          $u1 = $dg->create_user();
3470  
3471          $plan = $lpg->create_plan((object) array('userid' => $u1->id));
3472  
3473          $f1 = $lpg->create_framework();
3474          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3475          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3476          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3477          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3478          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3479          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3480  
3481          // Create user competency plan.
3482          $uc2 = $lpg->create_user_competency_plan(array(
3483              'userid' => $u1->id,
3484              'competencyid' => $c11b->get('id'),
3485              'planid' => $plan->get('id')
3486          ));
3487  
3488          // We can not delete a competency , if competency or competency children exist in user competency plan.
3489          $this->assertFalse(api::delete_competency($c1a->get('id')));
3490  
3491          // We can delete the competency if we remove the competency from user competency plan.
3492          $uc2->delete();
3493  
3494          $this->assertTrue(api::delete_competency($c1a->get('id')));
3495          $this->assertFalse(competency::record_exists($c1a->get('id')));
3496          $this->assertFalse(competency::record_exists($c1b->get('id')));
3497          $this->assertFalse(competency::record_exists($c11b->get('id')));
3498          $this->assertFalse(competency::record_exists($c12b->get('id')));
3499      }
3500  
3501      public function test_delete_competency_used_in_template() {
3502          $this->resetAfterTest(true);
3503          $dg = $this->getDataGenerator();
3504          $lpg = $dg->get_plugin_generator('core_competency');
3505          $this->setAdminUser();
3506  
3507          $template = $lpg->create_template();
3508  
3509          $f1 = $lpg->create_framework();
3510          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3511          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3512          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3513          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3514          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3515          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3516  
3517          // Add competency to a template.
3518          $tc = $lpg->create_template_competency(array(
3519              'templateid' => $template->get('id'),
3520              'competencyid' => $c11b->get('id')
3521          ));
3522          // We can not delete a competency , if competency or competency children is linked to template.
3523          $this->assertFalse(api::delete_competency($c1a->get('id')));
3524  
3525          // We can delete the competency if we remove the competency from template.
3526          $tc->delete();
3527  
3528          $this->assertTrue(api::delete_competency($c1a->get('id')));
3529          $this->assertFalse(competency::record_exists($c1a->get('id')));
3530          $this->assertFalse(competency::record_exists($c1b->get('id')));
3531          $this->assertFalse(competency::record_exists($c11b->get('id')));
3532          $this->assertFalse(competency::record_exists($c12b->get('id')));
3533      }
3534  
3535      public function test_delete_competency_used_in_course() {
3536          $this->resetAfterTest(true);
3537          $dg = $this->getDataGenerator();
3538          $lpg = $dg->get_plugin_generator('core_competency');
3539          $this->setAdminUser();
3540  
3541          $cat1 = $dg->create_category();
3542  
3543          $course = $dg->create_course(array('category' => $cat1->id));
3544  
3545          $f1 = $lpg->create_framework();
3546          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3547          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3548          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3549          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3550          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3551          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3552  
3553          // Add competency to course.
3554          $cc = $lpg->create_course_competency(array(
3555              'courseid' => $course->id,
3556              'competencyid' => $c11b->get('id')
3557          ));
3558  
3559          // We can not delete a competency if the competency or competencies children is linked to a course.
3560          $this->assertFalse(api::delete_competency($c1a->get('id')));
3561  
3562          // We can delete the competency if we remove the competency from course.
3563          $cc->delete();
3564  
3565          $this->assertTrue(api::delete_competency($c1a->get('id')));
3566          $this->assertFalse(competency::record_exists($c1a->get('id')));
3567          $this->assertFalse(competency::record_exists($c1b->get('id')));
3568          $this->assertFalse(competency::record_exists($c11b->get('id')));
3569          $this->assertFalse(competency::record_exists($c12b->get('id')));
3570      }
3571  
3572      public function test_delete_framework() {
3573          $this->resetAfterTest(true);
3574          $dg = $this->getDataGenerator();
3575          $lpg = $dg->get_plugin_generator('core_competency');
3576          $this->setAdminUser();
3577  
3578          $u1 = $dg->create_user();
3579  
3580          $f1 = $lpg->create_framework();
3581          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3582          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3583          $c2id = $c2->get('id');
3584          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3585          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3586          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3587          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3588  
3589          // If we delete framework, the related competencies relations and evidences should be deleted.
3590          // Create related competencies using one of c1a competency descendants.
3591          $rc = $lpg->create_related_competency(array(
3592              'competencyid' => $c2->get('id'),
3593              'relatedcompetencyid' => $c11b->get('id')
3594          ));
3595          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3596  
3597          // Creating a standard evidence with minimal information.
3598          $uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3599          $evidence = $lpg->create_evidence(array('usercompetencyid' => $uc2->get('id')));
3600          $this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));
3601          $uc2->delete();
3602  
3603          $this->assertTrue(api::delete_framework($f1->get('id')));
3604          $this->assertFalse(competency_framework::record_exists($f1->get('id')));
3605  
3606          // Check that all competencies were also deleted.
3607          $this->assertFalse(competency::record_exists($c1->get('id')));
3608          $this->assertFalse(competency::record_exists($c2->get('id')));
3609          $this->assertFalse(competency::record_exists($c1a->get('id')));
3610          $this->assertFalse(competency::record_exists($c1b->get('id')));
3611          $this->assertFalse(competency::record_exists($c11b->get('id')));
3612          $this->assertFalse(competency::record_exists($c12b->get('id')));
3613  
3614          // Check if evidence are also deleted.
3615          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3616  
3617          // Check if related conpetency relation is deleted.
3618          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3619  
3620          // Delete a simple framework.
3621          $f2 = $lpg->create_framework();
3622          $this->assertTrue(api::delete_framework($f2->get('id')));
3623          $this->assertFalse(competency_framework::record_exists($f2->get('id')));
3624      }
3625  
3626      public function test_delete_framework_competency_used_in_plan() {
3627          $this->resetAfterTest(true);
3628          $dg = $this->getDataGenerator();
3629          $lpg = $dg->get_plugin_generator('core_competency');
3630          $this->setAdminUser();
3631  
3632          $u1 = $dg->create_user();
3633  
3634          $plan = $lpg->create_plan((object) array('userid' => $u1->id));
3635  
3636          $f1 = $lpg->create_framework();
3637          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3638          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3639          $c2id = $c2->get('id');
3640          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3641          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3642          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3643          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3644  
3645          // Create related competencies.
3646          $rc = $lpg->create_related_competency(array(
3647              'competencyid' => $c2->get('id'),
3648              'relatedcompetencyid' => $c11b->get('id')
3649          ));
3650          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3651  
3652          // Creating a standard evidence with minimal information.
3653          $uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3654          $usercompetencyid = $uc2->get('id');
3655          $evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));
3656          $this->assertEquals($uc2->get('id'), $evidence->get('usercompetencyid'));
3657          $uc2->delete();
3658  
3659          // Add competency to plan.
3660          $pc = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $c11b->get('id')));
3661          // We can not delete a framework , if competency or competency children is associated to plan.
3662          $this->assertFalse(api::delete_framework($f1->get('id')));
3663          // Check that none of associated data are deleted.
3664          $this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));
3665          $this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));
3666  
3667          // We can delete the competency if we remove the competency from the plan.
3668          $pc->delete();
3669  
3670          $this->assertTrue(api::delete_framework($f1->get('id')));
3671          $this->assertFalse(competency::record_exists($c1->get('id')));
3672          $this->assertFalse(competency::record_exists($c2->get('id')));
3673          $this->assertFalse(competency::record_exists($c1a->get('id')));
3674          $this->assertFalse(competency::record_exists($c1b->get('id')));
3675          $this->assertFalse(competency::record_exists($c11b->get('id')));
3676          $this->assertFalse(competency::record_exists($c12b->get('id')));
3677          // Check if evidence are also deleted.
3678          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3679  
3680          // Check if related conpetency relation is deleted.
3681          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3682      }
3683  
3684      public function test_delete_framework_competency_used_in_usercompetency() {
3685          $this->resetAfterTest(true);
3686          $dg = $this->getDataGenerator();
3687          $lpg = $dg->get_plugin_generator('core_competency');
3688          $this->setAdminUser();
3689  
3690          $u1 = $dg->create_user();
3691  
3692          $f1 = $lpg->create_framework();
3693          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3694          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3695          $c2id = $c2->get('id');
3696          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3697          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3698          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3699          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3700  
3701          // Create related competencies.
3702          $rc = $lpg->create_related_competency(array(
3703              'competencyid' => $c2->get('id'),
3704              'relatedcompetencyid' => $c11b->get('id')
3705          ));
3706          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3707  
3708          // Creating a standard evidence with minimal information.
3709          $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3710          $usercompetencyid = $uc1->get('id');
3711          $evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));
3712          $this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));
3713          $uc1->delete();
3714  
3715          // Create user competency.
3716          $uc2 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3717  
3718          // We can not delete a framework , if competency or competency children exist in user competency.
3719          $this->assertFalse(api::delete_framework($f1->get('id')));
3720          // Check that none of associated data are deleted.
3721          $this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));
3722          $this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));
3723  
3724          // We can delete the framework if we remove the competency from user competency.
3725          $uc2->delete();
3726  
3727          $this->assertTrue(api::delete_framework($f1->get('id')));
3728          $this->assertFalse(competency::record_exists($c1->get('id')));
3729          $this->assertFalse(competency::record_exists($c2->get('id')));
3730          $this->assertFalse(competency::record_exists($c1a->get('id')));
3731          $this->assertFalse(competency::record_exists($c1b->get('id')));
3732          $this->assertFalse(competency::record_exists($c11b->get('id')));
3733          $this->assertFalse(competency::record_exists($c12b->get('id')));
3734          // Check if evidence are also deleted.
3735          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3736  
3737          // Check if related conpetency relation is deleted.
3738          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3739      }
3740  
3741      public function test_delete_framework_competency_used_in_usercompetencyplan() {
3742          $this->resetAfterTest(true);
3743          $dg = $this->getDataGenerator();
3744          $lpg = $dg->get_plugin_generator('core_competency');
3745          $this->setAdminUser();
3746  
3747          $u1 = $dg->create_user();
3748  
3749          $plan = $lpg->create_plan((object) array('userid' => $u1->id));
3750  
3751          $f1 = $lpg->create_framework();
3752          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3753          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3754          $c2id = $c2->get('id');
3755          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3756          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3757          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3758          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3759  
3760          // Create related competencies.
3761          $rc = $lpg->create_related_competency(array(
3762              'competencyid' => $c2->get('id'),
3763              'relatedcompetencyid' => $c11b->get('id')
3764          ));
3765          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3766  
3767          // Creating a standard evidence with minimal information.
3768          $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3769          $usercompetencyid = $uc1->get('id');
3770          $evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));
3771          $this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));
3772          $uc1->delete();
3773  
3774          // Create user competency plan.
3775          $uc2 = $lpg->create_user_competency_plan(array(
3776              'userid' => $u1->id,
3777              'competencyid' => $c11b->get('id'),
3778              'planid' => $plan->get('id')
3779          ));
3780  
3781          // We can not delete a framework , if competency or competency children exist in user competency plan.
3782          $this->assertFalse(api::delete_framework($f1->get('id')));
3783          // Check that none of associated data are deleted.
3784          $this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));
3785          $this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));
3786  
3787          // We can delete the framework if we remove the competency from user competency plan.
3788          $uc2->delete();
3789  
3790          $this->assertTrue(api::delete_framework($f1->get('id')));
3791          $this->assertFalse(competency::record_exists($c1->get('id')));
3792          $this->assertFalse(competency::record_exists($c2->get('id')));
3793          $this->assertFalse(competency::record_exists($c1a->get('id')));
3794          $this->assertFalse(competency::record_exists($c1b->get('id')));
3795          $this->assertFalse(competency::record_exists($c11b->get('id')));
3796          $this->assertFalse(competency::record_exists($c12b->get('id')));
3797          // Check if evidence are also deleted.
3798          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3799  
3800          // Check if related conpetency relation is deleted.
3801          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3802      }
3803  
3804      public function test_delete_framework_competency_used_in_template() {
3805          $this->resetAfterTest(true);
3806          $dg = $this->getDataGenerator();
3807          $lpg = $dg->get_plugin_generator('core_competency');
3808          $this->setAdminUser();
3809  
3810          $u1 = $dg->create_user();
3811          $template = $lpg->create_template();
3812  
3813          $f1 = $lpg->create_framework();
3814          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3815          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3816          $c2id = $c2->get('id');
3817          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3818          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3819          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3820          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3821  
3822          // Create related competencies.
3823          $rc = $lpg->create_related_competency(array(
3824              'competencyid' => $c2->get('id'),
3825              'relatedcompetencyid' => $c11b->get('id')
3826          ));
3827          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3828  
3829          // Creating a standard evidence with minimal information.
3830          $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3831          $usercompetencyid = $uc1->get('id');
3832          $evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));
3833          $this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));
3834          $uc1->delete();
3835  
3836          // Add competency to a template.
3837          $tc = $lpg->create_template_competency(array(
3838              'templateid' => $template->get('id'),
3839              'competencyid' => $c11b->get('id')
3840          ));
3841          // We can not delete a framework , if competency or competency children is linked to template.
3842          $this->assertFalse(api::delete_framework($f1->get('id')));
3843          // Check that none of associated data are deleted.
3844          $this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));
3845          $this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));
3846  
3847          // We can delete the framework if we remove the competency from template.
3848          $tc->delete();
3849  
3850          $this->assertTrue(api::delete_framework($f1->get('id')));
3851          $this->assertFalse(competency::record_exists($c1->get('id')));
3852          $this->assertFalse(competency::record_exists($c2->get('id')));
3853          $this->assertFalse(competency::record_exists($c1a->get('id')));
3854          $this->assertFalse(competency::record_exists($c1b->get('id')));
3855          $this->assertFalse(competency::record_exists($c11b->get('id')));
3856          $this->assertFalse(competency::record_exists($c12b->get('id')));
3857          // Check if evidence are also deleted.
3858          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3859  
3860          // Check if related conpetency relation is deleted.
3861          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3862      }
3863  
3864      public function test_delete_framework_competency_used_in_course() {
3865          $this->resetAfterTest(true);
3866          $dg = $this->getDataGenerator();
3867          $lpg = $dg->get_plugin_generator('core_competency');
3868          $this->setAdminUser();
3869  
3870          $cat1 = $dg->create_category();
3871          $u1 = $dg->create_user();
3872          $course = $dg->create_course(array('category' => $cat1->id));
3873  
3874          $f1 = $lpg->create_framework();
3875          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3876          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
3877          $c2id = $c2->get('id');
3878          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1->get('id')));
3879          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1a->get('id')));
3880          $c11b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3881          $c12b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'parentid' => $c1b->get('id')));
3882  
3883          // Create related competencies.
3884          $rc = $lpg->create_related_competency(array(
3885              'competencyid' => $c2->get('id'),
3886              'relatedcompetencyid' => $c11b->get('id')
3887          ));
3888          $this->assertEquals($c11b->get('id'), $rc->get('relatedcompetencyid'));
3889  
3890          // Creating a standard evidence with minimal information.
3891          $uc1 = $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $c11b->get('id')));
3892          $usercompetencyid = $uc1->get('id');
3893          $evidence = $lpg->create_evidence(array('usercompetencyid' => $usercompetencyid));
3894          $this->assertEquals($uc1->get('id'), $evidence->get('usercompetencyid'));
3895          $uc1->delete();
3896  
3897          // Add competency to course.
3898          $cc = $lpg->create_course_competency(array(
3899              'courseid' => $course->id,
3900              'competencyid' => $c11b->get('id')
3901          ));
3902  
3903          // We can not delete a framework if the competency or competencies children is linked to a course.
3904          $this->assertFalse(api::delete_framework($f1->get('id')));
3905          // Check that none of associated data are deleted.
3906          $this->assertEquals($usercompetencyid, $evidence->read()->get('usercompetencyid'));
3907          $this->assertEquals($c2->get('id'), $rc->read()->get('competencyid'));
3908  
3909          // We can delete the framework if we remove the competency from course.
3910          $cc->delete();
3911  
3912          $this->assertTrue(api::delete_framework($f1->get('id')));
3913          $this->assertFalse(competency::record_exists($c1->get('id')));
3914          $this->assertFalse(competency::record_exists($c2->get('id')));
3915          $this->assertFalse(competency::record_exists($c1a->get('id')));
3916          $this->assertFalse(competency::record_exists($c1b->get('id')));
3917          $this->assertFalse(competency::record_exists($c11b->get('id')));
3918          $this->assertFalse(competency::record_exists($c12b->get('id')));
3919          // Check if evidence are also deleted.
3920          $this->assertEquals(0, \core_competency\user_evidence_competency::count_records(array('competencyid' => $c11b->get('id'))));
3921  
3922          // Check if related conpetency relation is deleted.
3923          $this->assertEquals(0, count(\core_competency\related_competency::get_multiple_relations(array($c2id))));
3924      }
3925  
3926      public function test_grade_competency_in_course_permissions() {
3927          $this->resetAfterTest();
3928          $dg = $this->getDataGenerator();
3929  
3930          $c1 = $dg->create_course();
3931          $c2 = $dg->create_course();
3932          $sysctx = context_system::instance();
3933          $c1ctx = context_course::instance($c1->id);
3934          $c2ctx = context_course::instance($c2->id);
3935  
3936          $teacher1 = $dg->create_user();
3937          $noneditingteacher = $dg->create_user();
3938          $student1 = $dg->create_user();
3939          $student2 = $dg->create_user();
3940          $notstudent1 = $dg->create_user();
3941  
3942          $lpg = $dg->get_plugin_generator('core_competency');
3943          $framework = $lpg->create_framework();
3944          $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
3945          $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
3946          $lpg->create_course_competency(array('courseid' => $c1->id, 'competencyid' => $comp1->get('id')));
3947  
3948          $studentarch = get_archetype_roles('student');
3949          $studentrole = array_shift($studentarch);
3950  
3951          $gradablerole = $dg->create_role();
3952          assign_capability('moodle/competency:coursecompetencygradable', CAP_ALLOW, $gradablerole, $sysctx->id);
3953  
3954          $notgradablerole = $dg->create_role();
3955          assign_capability('moodle/competency:coursecompetencygradable', CAP_PROHIBIT, $notgradablerole, $sysctx->id);
3956  
3957          $canviewucrole = $dg->create_role();
3958          assign_capability('moodle/competency:usercompetencyview', CAP_ALLOW, $canviewucrole, $sysctx->id);
3959  
3960          $cannotviewcomp = $dg->create_role();
3961          assign_capability('moodle/competency:competencyview', CAP_PROHIBIT, $cannotviewcomp, $sysctx->id);
3962  
3963          $canmanagecomp = $dg->create_role();
3964          assign_capability('moodle/competency:competencymanage', CAP_ALLOW, $canmanagecomp, $sysctx->id);
3965  
3966          $cangraderole = $dg->create_role();
3967          assign_capability('moodle/competency:competencygrade', CAP_ALLOW, $cangraderole, $sysctx->id);
3968  
3969          // Enrol s1 and s2 as students in course 1.
3970          $dg->enrol_user($student1->id, $c1->id, $studentrole->id);
3971          $dg->enrol_user($student2->id, $c1->id, $studentrole->id);
3972  
3973          // Mark the s2 as not being 'gradable'.
3974          $dg->role_assign($notgradablerole, $student2->id, $c1ctx->id);
3975  
3976          // Mark the 'non a student' as 'gradable' throughout the site.
3977          $dg->role_assign($gradablerole, $notstudent1->id, $sysctx->id);
3978  
3979          // From now we'll iterate over each permission.
3980          accesslib_clear_all_caches_for_unit_testing();
3981          $this->setUser($teacher1);
3982  
3983          $this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'View a user competency',
3984              $c1->id, $student1->id, $comp1->get('id'));
3985  
3986          // Give permission to view competencies.
3987          $dg->role_assign($canviewucrole, $teacher1->id, $c1ctx->id);
3988          accesslib_clear_all_caches_for_unit_testing();
3989          $this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'Set competency rating',
3990              $c1->id, $student1->id, $comp1->get('id'));
3991  
3992          // Give permission to rate.
3993          $dg->role_assign($cangraderole, $teacher1->id, $c1ctx->id);
3994          accesslib_clear_all_caches_for_unit_testing();
3995          $this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));
3996  
3997          // Remove permssion to read competencies, this leads to error.
3998          $dg->role_assign($cannotviewcomp, $teacher1->id, $sysctx->id);
3999          accesslib_clear_all_caches_for_unit_testing();
4000          $this->assertExceptionWithGradeCompetencyInCourse('required_capability_exception', 'View competency frameworks',
4001              $c1->id, $student1->id, $comp1->get('id'));
4002  
4003          // Give permssion to manage course competencies, this leads to success.
4004          $dg->role_assign($canmanagecomp, $teacher1->id, $sysctx->id);
4005          accesslib_clear_all_caches_for_unit_testing();
4006          $this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));
4007  
4008          // Try to grade a user that is not gradable, lead to errors.
4009          $this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency may not be rated at this time.',
4010              $c1->id, $student2->id, $comp1->get('id'));
4011  
4012          // Try to grade a competency not in the course.
4013          $this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency does not belong to this course',
4014              $c1->id, $student1->id, $comp2->get('id'));
4015  
4016          // Try to grade a user that is not enrolled, even though they are 'gradable'.
4017          $this->assertExceptionWithGradeCompetencyInCourse('coding_exception', 'The competency may not be rated at this time.',
4018              $c1->id, $notstudent1->id, $comp1->get('id'));
4019  
4020          // Give permission for non-editing teacher to grade.
4021          $dg->role_assign($canviewucrole, $noneditingteacher->id, $c1ctx->id);
4022          $dg->role_assign($cangraderole, $noneditingteacher->id, $c1ctx->id);
4023          $this->setUser($noneditingteacher);
4024  
4025          accesslib_clear_all_caches_for_unit_testing();
4026          $this->assertSuccessWithGradeCompetencyInCourse($c1->id, $student1->id, $comp1->get('id'));
4027      }
4028  
4029      /**
4030       * Assert that a competency was graded in a course.
4031       *
4032       * @param int $courseid The course ID.
4033       * @param int $userid The user ID.
4034       * @param int $compid The competency ID.
4035       * @param int $grade The grade.
4036       */
4037      protected function assertSuccessWithGradeCompetencyInCourse($courseid, $userid, $compid, $grade = 1) {
4038          $beforecount = evidence::count_records();
4039          api::grade_competency_in_course($courseid, $userid, $compid, $grade);
4040          $this->assertEquals($beforecount + 1, evidence::count_records());
4041          $uc = user_competency::get_record(array('userid' => $userid, 'competencyid' => $compid));
4042          $records = evidence::get_records(array(), 'id', 'DESC', 0, 1);
4043          $evidence = array_pop($records);
4044          $this->assertEquals($uc->get('id'), $evidence->get('usercompetencyid'));
4045      }
4046  
4047      /**
4048       * Assert that grading a competency in course throws an exception.
4049       *
4050       * @param string $exceptiontype The exception type.
4051       * @param string $exceptiontest The exceptiont text.
4052       * @param int $courseid The course ID.
4053       * @param int $userid The user ID.
4054       * @param int $compid The competency ID.
4055       * @param int $grade The grade.
4056       */
4057      protected function assertExceptionWithGradeCompetencyInCourse($exceptiontype, $exceptiontext, $courseid, $userid, $compid,
4058                                                                    $grade = 1) {
4059  
4060          $raised = false;
4061          try {
4062              api::grade_competency_in_course($courseid, $userid, $compid, $grade);
4063          } catch (moodle_exception $e) {
4064              $raised = true;
4065              $this->assertInstanceOf($exceptiontype, $e);
4066              $this->assertRegExp('@' . $exceptiontext . '@', $e->getMessage());
4067          }
4068  
4069          if (!$raised) {
4070              $this->fail('Grading should not be allowed.');
4071          }
4072      }
4073  
4074      /**
4075       * Test list of evidences for plan completed and not completed.
4076       */
4077      public function test_list_evidence() {
4078          global $DB;
4079  
4080          $this->resetAfterTest(true);
4081          $dg = $this->getDataGenerator();
4082          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
4083  
4084          $syscontext = context_system::instance();
4085  
4086          // Create users.
4087          $user = $dg->create_user();
4088          $this->setUser($user);
4089  
4090          // Create a framework and assign competencies.
4091          $framework = $lpg->create_framework();
4092          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4093          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4094  
4095          // Create 2 user plans and add competency to each plan.
4096          $p1 = $lpg->create_plan(array('userid' => $user->id));
4097          $p2 = $lpg->create_plan(array('userid' => $user->id));
4098          $pc1 = $lpg->create_plan_competency(array('planid' => $p1->get('id'), 'competencyid' => $c1->get('id')));
4099          $pc2 = $lpg->create_plan_competency(array('planid' => $p2->get('id'), 'competencyid' => $c1->get('id')));
4100  
4101          // Create user competency and add an evidence.
4102          $uc = $lpg->create_user_competency(array('userid' => $user->id, 'competencyid' => $c1->get('id')));
4103          $e1 = $lpg->create_evidence(array('usercompetencyid' => $uc->get('id')));
4104  
4105          // Check both plans as one evidence.
4106          $this->assertEquals(1, count(api::list_evidence($user->id, $c1->get('id'), $p1->get('id'))));
4107          $this->assertEquals(1, count(api::list_evidence($user->id, $c1->get('id'), $p2->get('id'))));
4108  
4109          // Complete second plan.
4110          $p2->set('status', plan::STATUS_COMPLETE);
4111          $p2->update();
4112  
4113          // Add another evidence for the same competency, but in the future (time + 1).
4114          $e2 = $lpg->create_evidence(array('usercompetencyid' => $uc->get('id')));
4115          $evidencesql = "UPDATE {" . evidence::TABLE . "} SET timecreated = :currenttime WHERE id = :evidenceid";
4116          $DB->execute($evidencesql, array('currenttime' => time() + 1, 'evidenceid' => $e2->get('id')));
4117  
4118          // Check that the first plan, which is not completed, has all the evidence.
4119          $this->assertEquals(2, count(api::list_evidence($user->id, $c1->get('id'), $p1->get('id'))));
4120  
4121          // Check that the second plan, completed before the new evidence, only has the first piece of evidence.
4122          $listevidences = api::list_evidence($user->id, $c1->get('id'), $p2->get('id'));
4123          $this->assertEquals(1, count($listevidences));
4124          $this->assertEquals($e1->get('id'), $listevidences[$e1->get('id')]->get('id'));
4125      }
4126  
4127      /**
4128       * Get a user competency in a course.
4129       */
4130      public function test_get_user_competency_in_course() {
4131          $this->resetAfterTest(true);
4132          $dg = $this->getDataGenerator();
4133          $lpg = $dg->get_plugin_generator('core_competency');
4134          $this->setAdminUser();
4135  
4136          $user = $dg->create_user();
4137          $c1 = $dg->create_course();
4138  
4139          // Enrol the user so they can be rated in the course.
4140          $studentarch = get_archetype_roles('student');
4141          $studentrole = array_shift($studentarch);
4142          $coursecontext = context_course::instance($c1->id);
4143          $dg->role_assign($studentrole->id, $user->id, $coursecontext->id);
4144          $dg->enrol_user($user->id, $c1->id, $studentrole->id);
4145  
4146          $framework = $lpg->create_framework();
4147          $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4148          $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4149          $lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));
4150          $lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));
4151  
4152          // Create a user competency for comp1.
4153          api::grade_competency_in_course($c1, $user->id, $comp1->get('id'), 3, 'Unit test');
4154  
4155          // Test for competency already exist in user_competency.
4156          $uc = api::get_user_competency_in_course($c1->id, $user->id, $comp1->get('id'));
4157          $this->assertEquals($comp1->get('id'), $uc->get('competencyid'));
4158          $this->assertEquals($user->id, $uc->get('userid'));
4159          $this->assertEquals(3, $uc->get('grade'));
4160          $this->assertEquals(true, $uc->get('proficiency'));
4161  
4162          // Test for competency does not exist in user_competency.
4163          $uc2 = api::get_user_competency_in_course($c1->id, $user->id, $comp2->get('id'));
4164          $this->assertEquals($comp2->get('id'), $uc2->get('competencyid'));
4165          $this->assertEquals($user->id, $uc2->get('userid'));
4166          $this->assertEquals(null, $uc2->get('grade'));
4167          $this->assertEquals(null, $uc2->get('proficiency'));
4168      }
4169  
4170      /**
4171       * Test course statistics api functions.
4172       */
4173      public function test_course_statistics() {
4174          $this->resetAfterTest(true);
4175          $dg = $this->getDataGenerator();
4176          $lpg = $dg->get_plugin_generator('core_competency');
4177          $this->setAdminUser();
4178  
4179          $u1 = $dg->create_user();
4180          $u2 = $dg->create_user();
4181          $u3 = $dg->create_user();
4182          $u4 = $dg->create_user();
4183          $c1 = $dg->create_course();
4184          $framework = $lpg->create_framework();
4185          // Enrol students in the course.
4186          $studentarch = get_archetype_roles('student');
4187          $studentrole = array_shift($studentarch);
4188          $coursecontext = context_course::instance($c1->id);
4189          $dg->role_assign($studentrole->id, $u1->id, $coursecontext->id);
4190          $dg->enrol_user($u1->id, $c1->id, $studentrole->id);
4191          $dg->role_assign($studentrole->id, $u2->id, $coursecontext->id);
4192          $dg->enrol_user($u2->id, $c1->id, $studentrole->id);
4193          $dg->role_assign($studentrole->id, $u3->id, $coursecontext->id);
4194          $dg->enrol_user($u3->id, $c1->id, $studentrole->id);
4195          $dg->role_assign($studentrole->id, $u4->id, $coursecontext->id);
4196          $dg->enrol_user($u4->id, $c1->id, $studentrole->id);
4197  
4198          // Create 6 competencies.
4199          $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4200          $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4201          $comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4202          $comp4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4203          $comp5 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4204          $comp6 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4205  
4206          // Link 6 out of 6 to a course.
4207          $lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));
4208          $lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));
4209          $lpg->create_course_competency(array('competencyid' => $comp3->get('id'), 'courseid' => $c1->id));
4210          $lpg->create_course_competency(array('competencyid' => $comp4->get('id'), 'courseid' => $c1->id));
4211          $lpg->create_course_competency(array('competencyid' => $comp5->get('id'), 'courseid' => $c1->id));
4212          $lpg->create_course_competency(array('competencyid' => $comp6->get('id'), 'courseid' => $c1->id));
4213  
4214          // Rate some competencies.
4215          // User 1.
4216          api::grade_competency_in_course($c1, $u1->id, $comp1->get('id'), 4, 'Unit test');
4217          api::grade_competency_in_course($c1, $u1->id, $comp2->get('id'), 4, 'Unit test');
4218          api::grade_competency_in_course($c1, $u1->id, $comp3->get('id'), 4, 'Unit test');
4219          api::grade_competency_in_course($c1, $u1->id, $comp4->get('id'), 4, 'Unit test');
4220          // User 2.
4221          api::grade_competency_in_course($c1, $u2->id, $comp1->get('id'), 1, 'Unit test');
4222          api::grade_competency_in_course($c1, $u2->id, $comp2->get('id'), 1, 'Unit test');
4223          api::grade_competency_in_course($c1, $u2->id, $comp3->get('id'), 1, 'Unit test');
4224          api::grade_competency_in_course($c1, $u2->id, $comp4->get('id'), 1, 'Unit test');
4225          // User 3.
4226          api::grade_competency_in_course($c1, $u3->id, $comp1->get('id'), 3, 'Unit test');
4227          api::grade_competency_in_course($c1, $u3->id, $comp2->get('id'), 3, 'Unit test');
4228          // User 4.
4229          api::grade_competency_in_course($c1, $u4->id, $comp1->get('id'), 2, 'Unit test');
4230          api::grade_competency_in_course($c1, $u4->id, $comp2->get('id'), 2, 'Unit test');
4231  
4232          // OK we have enough data - lets call some API functions and check for expected results.
4233  
4234          $result = api::count_proficient_competencies_in_course_for_user($c1->id, $u1->id);
4235          $this->assertEquals(4, $result);
4236          $result = api::count_proficient_competencies_in_course_for_user($c1->id, $u2->id);
4237          $this->assertEquals(0, $result);
4238          $result = api::count_proficient_competencies_in_course_for_user($c1->id, $u3->id);
4239          $this->assertEquals(2, $result);
4240          $result = api::count_proficient_competencies_in_course_for_user($c1->id, $u4->id);
4241          $this->assertEquals(0, $result);
4242  
4243          $result = api::get_least_proficient_competencies_for_course($c1->id, 0, 2);
4244          // We should get 5 and 6 in repeatable order.
4245          $valid = false;
4246          if (($comp5->get('id') == $result[0]->get('id')) || ($comp6->get('id') == $result[0]->get('id'))) {
4247              $valid = true;
4248          }
4249          $this->assertTrue($valid);
4250          $valid = false;
4251          if (($comp5->get('id') == $result[1]->get('id')) || ($comp6->get('id') == $result[1]->get('id'))) {
4252              $valid = true;
4253          }
4254          $this->assertTrue($valid);
4255          $expected = $result[1]->get('id');
4256          $result = api::get_least_proficient_competencies_for_course($c1->id, 1, 1);
4257          $this->assertEquals($result[0]->get('id'), $expected);
4258      }
4259  
4260      /**
4261       * Test template statistics api functions.
4262       */
4263      public function test_template_statistics() {
4264          $this->resetAfterTest(true);
4265          $dg = $this->getDataGenerator();
4266          $lpg = $dg->get_plugin_generator('core_competency');
4267          $this->setAdminUser();
4268  
4269          $u1 = $dg->create_user();
4270          $u2 = $dg->create_user();
4271          $u3 = $dg->create_user();
4272          $u4 = $dg->create_user();
4273          $c1 = $dg->create_course();
4274          $framework = $lpg->create_framework();
4275  
4276          // Create 6 competencies.
4277          $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4278          $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4279          $comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4280          $comp4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4281          $comp5 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4282          $comp6 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4283  
4284          // Link 5 out of 6 to a course.
4285          $lpg->create_course_competency(array('competencyid' => $comp1->get('id'), 'courseid' => $c1->id));
4286          $lpg->create_course_competency(array('competencyid' => $comp2->get('id'), 'courseid' => $c1->id));
4287          $lpg->create_course_competency(array('competencyid' => $comp3->get('id'), 'courseid' => $c1->id));
4288          $lpg->create_course_competency(array('competencyid' => $comp4->get('id'), 'courseid' => $c1->id));
4289          $lpg->create_course_competency(array('competencyid' => $comp5->get('id'), 'courseid' => $c1->id));
4290  
4291          // Put all 6 in a template.
4292          $tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();
4293          $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp1->get('id')));
4294          $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp2->get('id')));
4295          $tplc3 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp3->get('id')));
4296          $tplc4 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp4->get('id')));
4297          $tplc5 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp5->get('id')));
4298          $tplc6 = $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $comp6->get('id')));
4299  
4300          // Create some plans from the template.
4301          $p1 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u1->id));
4302          $p2 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u2->id));
4303          $p3 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u3->id));
4304          $p4 = $lpg->create_plan(array('templateid' => $tpl->get('id'), 'userid' => $u4->id));
4305  
4306          // Rate some competencies.
4307          // User 1.
4308          $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp1->get('id'),
4309                  'proficiency' => true, 'grade' => 1 ));
4310          $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp2->get('id'),
4311                  'proficiency' => true, 'grade' => 1 ));
4312          $lpg->create_user_competency(array('userid' => $u1->id, 'competencyid' => $comp3->get('id'),
4313                  'proficiency' => true, 'grade' => 1 ));
4314          // User 2.
4315          $lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp1->get('id'),
4316                  'proficiency' => false, 'grade' => 1 ));
4317          $lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp2->get('id'),
4318                  'proficiency' => false, 'grade' => 1 ));
4319          $lpg->create_user_competency(array('userid' => $u2->id, 'competencyid' => $comp3->get('id'),
4320                  'proficiency' => false, 'grade' => 1 ));
4321          // User 3.
4322          $lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp2->get('id'),
4323                  'proficiency' => false, 'grade' => 1 ));
4324          $lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp3->get('id'),
4325                  'proficiency' => true, 'grade' => 1 ));
4326          $lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp4->get('id'),
4327                  'proficiency' => false, 'grade' => 1 ));
4328          $lpg->create_user_competency(array('userid' => $u3->id, 'competencyid' => $comp5->get('id'),
4329                  'proficiency' => true, 'grade' => 1 ));
4330          // User 4.
4331          $lpg->create_user_competency(array('userid' => $u4->id, 'competencyid' => $comp3->get('id'),
4332                  'proficiency' => true, 'grade' => 1 ));
4333          $lpg->create_user_competency(array('userid' => $u4->id, 'competencyid' => $comp5->get('id'),
4334                  'proficiency' => true, 'grade' => 1 ));
4335  
4336          // Complete 3 out of 4 plans.
4337          api::complete_plan($p1->get('id'));
4338          api::complete_plan($p2->get('id'));
4339          api::complete_plan($p3->get('id'));
4340  
4341          // OK we have enough data - lets call some API functions and check for expected results.
4342  
4343          $result = api::count_competencies_in_template_with_no_courses($tpl->get('id'));
4344          $this->assertEquals(1, $result);
4345  
4346          $result = api::count_plans_for_template($tpl->get('id'));
4347          $this->assertEquals(4, $result);
4348  
4349          $result = api::count_plans_for_template($tpl->get('id'), plan::STATUS_COMPLETE);
4350          $this->assertEquals(3, $result);
4351  
4352          // This counts the records of competencies in completed plans for all users with a plan from this template.
4353          $result = api::count_user_competency_plans_for_template($tpl->get('id'));
4354          // There should be 3 plans * 6 competencies.
4355          $this->assertEquals(18, $result);
4356  
4357          // This counts the records of proficient competencies in completed plans for all users with a plan from this template.
4358          $result = api::count_user_competency_plans_for_template($tpl->get('id'), true);
4359          // There should be 5.
4360          $this->assertEquals(5, $result);
4361  
4362          // This counts the records of not proficient competencies in completed plans for all users with a plan from this template.
4363          $result = api::count_user_competency_plans_for_template($tpl->get('id'), false);
4364          // There should be 13.
4365          $this->assertEquals(13, $result);
4366  
4367          // This lists the plans based on this template, optionally filtered by status.
4368          $result = api::list_plans_for_template($tpl->get('id'));
4369  
4370          $this->assertEquals(4, count($result));
4371          foreach ($result as $one) {
4372              $this->assertInstanceOf('\core_competency\plan', $one);
4373          }
4374          // This lists the plans based on this template, optionally filtered by status.
4375          $result = api::list_plans_for_template($tpl->get('id'), plan::STATUS_COMPLETE);
4376  
4377          $this->assertEquals(3, count($result));
4378          foreach ($result as $one) {
4379              $this->assertInstanceOf('\core_competency\plan', $one);
4380              $this->assertEquals(plan::STATUS_COMPLETE, $one->get('status'));
4381          }
4382  
4383          $result = api::get_least_proficient_competencies_for_template($tpl->get('id'), 0, 2);
4384  
4385          // Our times completed counts should look like this:
4386          // - comp1 - 1
4387          // - comp2 - 1
4388          // - comp3 - 2
4389          // - comp4 - 0
4390          // - comp5 - 1
4391          // - comp6 - 0
4392          //
4393          // And this is a fullstop to make CiBoT happy.
4394          $this->assertEquals(2, count($result));
4395          $leastarray = array($comp4->get('id'), $comp6->get('id'));
4396          foreach ($result as $one) {
4397              $this->assertInstanceOf('\core_competency\competency', $one);
4398              $this->assertContains($one->get('id'), $leastarray);
4399          }
4400      }
4401  
4402      public function test_is_scale_used_anywhere() {
4403          $this->resetAfterTest();
4404          $dg = $this->getDataGenerator();
4405          $lpg = $dg->get_plugin_generator('core_competency');
4406  
4407          $scale1 = $dg->create_scale();
4408          $scale2 = $dg->create_scale();
4409          $scale3 = $dg->create_scale();
4410          $scale4 = $dg->create_scale();
4411  
4412          $this->assertFalse(api::is_scale_used_anywhere($scale1->id));
4413          $this->assertFalse(api::is_scale_used_anywhere($scale2->id));
4414          $this->assertFalse(api::is_scale_used_anywhere($scale3->id));
4415          $this->assertFalse(api::is_scale_used_anywhere($scale4->id));
4416  
4417          // Using scale 1 in a framework.
4418          $f1 = $lpg->create_framework([
4419              'scaleid' => $scale1->id,
4420              'scaleconfiguration' => json_encode([
4421                  ['scaleid' => $scale1->id],
4422                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4423              ])
4424          ]);
4425          $this->assertTrue(api::is_scale_used_anywhere($scale1->id));
4426          $this->assertFalse(api::is_scale_used_anywhere($scale2->id));
4427          $this->assertFalse(api::is_scale_used_anywhere($scale3->id));
4428          $this->assertFalse(api::is_scale_used_anywhere($scale4->id));
4429  
4430          // Using scale 2 in a competency.
4431          $f2 = $lpg->create_framework();
4432          $c2 = $lpg->create_competency([
4433              'competencyframeworkid' => $f2->get('id'),
4434              'scaleid' => $scale2->id,
4435              'scaleconfiguration' => json_encode([
4436                  ['scaleid' => $scale2->id],
4437                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4438              ])
4439          ]);
4440  
4441          $this->assertTrue(api::is_scale_used_anywhere($scale1->id));
4442          $this->assertTrue(api::is_scale_used_anywhere($scale2->id));
4443          $this->assertFalse(api::is_scale_used_anywhere($scale3->id));
4444          $this->assertFalse(api::is_scale_used_anywhere($scale4->id));
4445  
4446          // Using scale 3 in a framework, and scale 4 in a competency of that framework.
4447          $f3 = $lpg->create_framework([
4448              'scaleid' => $scale3->id,
4449              'scaleconfiguration' => json_encode([
4450                  ['scaleid' => $scale3->id],
4451                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4452              ])
4453          ]);
4454          $c3 = $lpg->create_competency([
4455              'competencyframeworkid' => $f3->get('id'),
4456              'scaleid' => $scale4->id,
4457              'scaleconfiguration' => json_encode([
4458                  ['scaleid' => $scale4->id],
4459                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4460              ])
4461          ]);
4462  
4463          $this->assertTrue(api::is_scale_used_anywhere($scale1->id));
4464          $this->assertTrue(api::is_scale_used_anywhere($scale2->id));
4465          $this->assertTrue(api::is_scale_used_anywhere($scale3->id));
4466          $this->assertTrue(api::is_scale_used_anywhere($scale4->id));
4467  
4468          // Multiple occurrences of the same scale (3, and 4).
4469          $f4 = $lpg->create_framework([
4470              'scaleid' => $scale3->id,
4471              'scaleconfiguration' => json_encode([
4472                  ['scaleid' => $scale3->id],
4473                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4474              ])
4475          ]);
4476          $c4 = $lpg->create_competency([
4477              'competencyframeworkid' => $f3->get('id'),
4478              'scaleid' => $scale4->id,
4479              'scaleconfiguration' => json_encode([
4480                  ['scaleid' => $scale4->id],
4481                  ['id' => 1, 'scaledefault' => 1, 'proficient' => 1]
4482              ])
4483          ]);
4484          $this->assertTrue(api::is_scale_used_anywhere($scale1->id));
4485          $this->assertTrue(api::is_scale_used_anywhere($scale2->id));
4486          $this->assertTrue(api::is_scale_used_anywhere($scale3->id));
4487          $this->assertTrue(api::is_scale_used_anywhere($scale4->id));
4488      }
4489  
4490      public function test_delete_evidence() {
4491          $this->resetAfterTest();
4492          $dg = $this->getDataGenerator();
4493          $ccg = $dg->get_plugin_generator('core_competency');
4494  
4495          $u1 = $dg->create_user();
4496          $f1 = $ccg->create_framework();
4497          $comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4498          $uc1 = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]);
4499  
4500          $ev1 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);
4501          $ev2 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);
4502  
4503          $this->setAdminUser($u1);
4504  
4505          $this->assertEquals(2, evidence::count_records());
4506          api::delete_evidence($ev1);
4507          $this->assertEquals(1, evidence::count_records());
4508          $this->assertFalse(evidence::record_exists($ev1->get('id')));
4509          $this->assertTrue(evidence::record_exists($ev2->get('id')));
4510      }
4511  
4512      public function test_delete_evidence_without_permissions() {
4513          $this->resetAfterTest();
4514          $dg = $this->getDataGenerator();
4515          $ccg = $dg->get_plugin_generator('core_competency');
4516  
4517          $u1 = $dg->create_user();
4518          $f1 = $ccg->create_framework();
4519          $comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4520          $uc1 = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $comp1->get('id')]);
4521          $ev1 = $ccg->create_evidence(['usercompetencyid' => $uc1->get('id')]);
4522  
4523          $this->setUser($u1);
4524  
4525          $this->expectException(required_capability_exception::class);
4526          api::delete_evidence($ev1);
4527      }
4528  
4529      public function test_list_plans_to_review() {
4530          $dg = $this->getDataGenerator();
4531          $this->resetAfterTest();
4532          $ccg = $dg->get_plugin_generator('core_competency');
4533          $sysctx = context_system::instance();
4534          $this->setAdminUser();
4535  
4536          $reviewer = $dg->create_user();
4537          $roleallow = $dg->create_role();
4538          $roleprohibit = $dg->create_role();
4539          assign_capability('moodle/competency:planreview', CAP_ALLOW, $roleallow, $sysctx->id);
4540          assign_capability('moodle/competency:planreview', CAP_PROHIBIT, $roleprohibit, $sysctx->id);
4541          role_assign($roleallow, $reviewer->id, $sysctx->id);
4542          accesslib_clear_all_caches_for_unit_testing();
4543  
4544          $u1 = $dg->create_user();
4545          $u2 = $dg->create_user();
4546          $f1 = $ccg->create_framework();
4547          $comp1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4548          $p1a = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_WAITING_FOR_REVIEW]);
4549          $p1b = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_IN_REVIEW, 'reviewerid' => $reviewer->id]);
4550          $p1c = $ccg->create_plan(['userid' => $u1->id, 'status' => plan::STATUS_DRAFT]);
4551          $p2a = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_WAITING_FOR_REVIEW]);
4552          $p2b = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_IN_REVIEW]);
4553          $p2c = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_ACTIVE]);
4554          $p2d = $ccg->create_plan(['userid' => $u2->id, 'status' => plan::STATUS_ACTIVE]);
4555          api::complete_plan($p2d);
4556  
4557          // The reviewer can review all plans waiting for review, or in review where they are the reviewer.
4558          $this->setUser($reviewer);
4559          $result = api::list_plans_to_review();
4560          $this->assertEquals(3, $result['count']);
4561          $this->assertEquals($p1a->get('id'), $result['plans'][0]->plan->get('id'));
4562          $this->assertEquals($p1b->get('id'), $result['plans'][1]->plan->get('id'));
4563          $this->assertEquals($p2a->get('id'), $result['plans'][2]->plan->get('id'));
4564  
4565          // The reviewer cannot view the plans when they do not have the permission in the user's context.
4566          role_assign($roleprohibit, $reviewer->id, context_user::instance($u2->id)->id);
4567          accesslib_clear_all_caches_for_unit_testing();
4568          $result = api::list_plans_to_review();
4569          $this->assertEquals(2, $result['count']);
4570          $this->assertEquals($p1a->get('id'), $result['plans'][0]->plan->get('id'));
4571          $this->assertEquals($p1b->get('id'), $result['plans'][1]->plan->get('id'));
4572      }
4573  
4574      public function test_list_user_competencies_to_review() {
4575          global $CFG;
4576          require_once($CFG->dirroot . '/user/lib.php');
4577  
4578          $dg = $this->getDataGenerator();
4579          $this->resetAfterTest();
4580          $ccg = $dg->get_plugin_generator('core_competency');
4581          $sysctx = context_system::instance();
4582          $this->setAdminUser();
4583  
4584          $reviewer = $dg->create_user();
4585          $roleallow = $dg->create_role();
4586          $roleprohibit = $dg->create_role();
4587          assign_capability('moodle/competency:usercompetencyreview', CAP_ALLOW, $roleallow, $sysctx->id);
4588          assign_capability('moodle/competency:usercompetencyreview', CAP_PROHIBIT, $roleprohibit, $sysctx->id);
4589          role_assign($roleallow, $reviewer->id, $sysctx->id);
4590          accesslib_clear_all_caches_for_unit_testing();
4591  
4592          $u1 = $dg->create_user();
4593          $u2 = $dg->create_user();
4594          $u3 = $dg->create_user();
4595          $f1 = $ccg->create_framework();
4596          $c1 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4597          $c2 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4598          $c3 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4599          $c4 = $ccg->create_competency(['competencyframeworkid' => $f1->get('id')]);
4600          $uc1a = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c1->get('id'),
4601              'status' => user_competency::STATUS_IDLE]);
4602          $uc1b = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c2->get('id'),
4603              'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);
4604          $uc1c = $ccg->create_user_competency(['userid' => $u1->id, 'competencyid' => $c3->get('id'),
4605              'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $reviewer->id]);
4606          $uc2a = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c1->get('id'),
4607              'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);
4608          $uc2b = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c2->get('id'),
4609              'status' => user_competency::STATUS_IDLE]);
4610          $uc2c = $ccg->create_user_competency(['userid' => $u2->id, 'competencyid' => $c3->get('id'),
4611              'status' => user_competency::STATUS_IN_REVIEW]);
4612          $uc3a = $ccg->create_user_competency(['userid' => $u3->id, 'competencyid' => $c4->get('id'),
4613              'status' => user_competency::STATUS_WAITING_FOR_REVIEW]);
4614  
4615          // The reviewer can review all plans waiting for review, or in review where they are the reviewer.
4616          $this->setUser($reviewer);
4617          $result = api::list_user_competencies_to_review();
4618          $this->assertEquals(4, $result['count']);
4619          $this->assertEquals($uc2a->get('id'), $result['competencies'][0]->usercompetency->get('id'));
4620          $this->assertEquals($uc1b->get('id'), $result['competencies'][1]->usercompetency->get('id'));
4621          $this->assertEquals($uc1c->get('id'), $result['competencies'][2]->usercompetency->get('id'));
4622          $this->assertEquals($uc3a->get('id'), $result['competencies'][3]->usercompetency->get('id'));
4623  
4624          // Now, let's delete user 3.
4625          // It should not be listed on user competencies to review any more.
4626          user_delete_user($u3);
4627          $result = api::list_user_competencies_to_review();
4628          $this->assertEquals(3, $result['count']);
4629  
4630          // The reviewer cannot view the plans when they do not have the permission in the user's context.
4631          role_assign($roleprohibit, $reviewer->id, context_user::instance($u2->id)->id);
4632          accesslib_clear_all_caches_for_unit_testing();
4633          $result = api::list_user_competencies_to_review();
4634          $this->assertEquals(2, $result['count']);
4635          $this->assertEquals($uc1b->get('id'), $result['competencies'][0]->usercompetency->get('id'));
4636          $this->assertEquals($uc1c->get('id'), $result['competencies'][1]->usercompetency->get('id'));
4637      }
4638  
4639      /**
4640       * Test we can get all of a users plans with a competency.
4641       */
4642      public function test_list_plans_with_competency() {
4643          $this->resetAfterTest(true);
4644          $this->setAdminUser();
4645          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
4646  
4647          $u1 = $this->getDataGenerator()->create_user();
4648          $tpl = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_template();
4649  
4650          // Create a framework and assign competencies.
4651          $framework = $lpg->create_framework();
4652          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
4653  
4654          // Create two plans and assign the competency to each.
4655          $plan1 = $lpg->create_plan(array('userid' => $u1->id));
4656          $plan2 = $lpg->create_plan(array('userid' => $u1->id));
4657  
4658          $lpg->create_plan_competency(array('planid' => $plan1->get('id'), 'competencyid' => $c1->get('id')));
4659          $lpg->create_plan_competency(array('planid' => $plan2->get('id'), 'competencyid' => $c1->get('id')));
4660  
4661          // Create one more plan without the competency.
4662          $plan3 = $lpg->create_plan(array('userid' => $u1->id));
4663  
4664          $plans = api::list_plans_with_competency($u1->id, $c1);
4665  
4666          $this->assertEquals(2, count($plans));
4667  
4668          $this->assertEquals(reset($plans)->get('id'), $plan1->get('id'));
4669          $this->assertEquals(end($plans)->get('id'), $plan2->get('id'));
4670      }
4671  
4672  }