Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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

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