Search moodle.org's
Developer Documentation

Long Term Support Release

  • Bug fixes for general core bugs in 3.5.x ended May 2019 (12 months).
  • Bug fixes for security issues in 3.5.x will end 10 May 2021 (36 months) - Support has ended.
  • minimum PHP 7.0.0 Note: minimum PHP version has increased since Moodle 3.3. PHP 7.1.x and 7.2.x are supported too. PHP 7.x could have some engine limitations.
  • Differences Between: [Versions 35 and 310] [Versions 35 and 311] [Versions 35 and 36] [Versions 35 and 37] [Versions 35 and 38] [Versions 35 and 39]

       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 =