Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]

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