Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   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  declare(strict_types = 1);
  18  
  19  namespace mod_choice;
  20  
  21  use advanced_testcase;
  22  use cm_info;
  23  use coding_exception;
  24  use mod_choice\completion\custom_completion;
  25  use moodle_exception;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  require_once($CFG->libdir . '/completionlib.php');
  31  
  32  /**
  33   * Class for unit testing mod_choice/custom_completion.
  34   *
  35   * @package   mod_choice
  36   * @copyright 2021 Jun Pataleta <jun@moodle.com>
  37   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class custom_completion_test extends advanced_testcase {
  40  
  41      /**
  42       * Data provider for get_state().
  43       *
  44       * @return array[]
  45       */
  46      public function get_state_provider(): array {
  47          return [
  48              'Undefined rule' => [
  49                  'somenonexistentrule', COMPLETION_DISABLED, false, null, coding_exception::class
  50              ],
  51              'Rule not available' => [
  52                  'completionsubmit', COMPLETION_DISABLED, false, null, moodle_exception::class
  53              ],
  54              'Rule available, user has not submitted' => [
  55                  'completionsubmit', COMPLETION_ENABLED, false, COMPLETION_INCOMPLETE, null
  56              ],
  57              'Rule available, user has submitted' => [
  58                  'completionsubmit', COMPLETION_ENABLED, true, COMPLETION_COMPLETE, null
  59              ],
  60          ];
  61      }
  62  
  63      /**
  64       * Test for get_state().
  65       *
  66       * @dataProvider get_state_provider
  67       * @param string $rule The custom completion rule.
  68       * @param int $available Whether this rule is available.
  69       * @param bool $submitted Whether the user has made a choice.
  70       * @param int|null $status Expected status.
  71       * @param string|null $exception Expected exception.
  72       */
  73      public function test_get_state(string $rule, int $available, ?bool $submitted, ?int $status, ?string $exception) {
  74          global $DB;
  75  
  76          if (!is_null($exception)) {
  77              $this->expectException($exception);
  78          }
  79  
  80          // Custom completion rule data for cm_info::customdata.
  81          $customdataval = [
  82              'customcompletionrules' => [
  83                  $rule => $available
  84              ]
  85          ];
  86  
  87          // Build a mock cm_info instance.
  88          $mockcminfo = $this->getMockBuilder(cm_info::class)
  89              ->disableOriginalConstructor()
  90              ->onlyMethods(['__get'])
  91              ->getMock();
  92  
  93          // Mock the return of the magic getter method when fetching the cm_info object's customdata and instance values.
  94          $mockcminfo->expects($this->any())
  95              ->method('__get')
  96              ->will($this->returnValueMap([
  97                  ['customdata', $customdataval],
  98                  ['instance', 1],
  99              ]));
 100  
 101          // Mock the DB calls.
 102          $DB = $this->createMock(get_class($DB));
 103          $DB->expects($this->atMost(1))
 104              ->method('record_exists')
 105              ->willReturn($submitted);
 106  
 107          $customcompletion = new custom_completion($mockcminfo, 2);
 108          $this->assertEquals($status, $customcompletion->get_state($rule));
 109      }
 110  
 111      /**
 112       * Test for get_defined_custom_rules().
 113       */
 114      public function test_get_defined_custom_rules() {
 115          $rules = custom_completion::get_defined_custom_rules();
 116          $this->assertCount(1, $rules);
 117          $this->assertEquals('completionsubmit', reset($rules));
 118      }
 119  
 120      /**
 121       * Test for get_defined_custom_rule_descriptions().
 122       */
 123      public function test_get_custom_rule_descriptions() {
 124          // Get defined custom rules.
 125          $rules = custom_completion::get_defined_custom_rules();
 126  
 127          // Build a mock cm_info instance.
 128          $mockcminfo = $this->getMockBuilder(cm_info::class)
 129              ->disableOriginalConstructor()
 130              ->onlyMethods(['__get'])
 131              ->getMock();
 132  
 133          // Instantiate a custom_completion object using the mocked cm_info.
 134          $customcompletion = new custom_completion($mockcminfo, 1);
 135  
 136          // Get custom rule descriptions.
 137          $ruledescriptions = $customcompletion->get_custom_rule_descriptions();
 138  
 139          // Confirm that defined rules and rule descriptions are consistent with each other.
 140          $this->assertEquals(count($rules), count($ruledescriptions));
 141          foreach ($rules as $rule) {
 142              $this->assertArrayHasKey($rule, $ruledescriptions);
 143          }
 144      }
 145  
 146      /**
 147       * Test for is_defined().
 148       */
 149      public function test_is_defined() {
 150          // Build a mock cm_info instance.
 151          $mockcminfo = $this->getMockBuilder(cm_info::class)
 152              ->disableOriginalConstructor()
 153              ->getMock();
 154  
 155          $customcompletion = new custom_completion($mockcminfo, 1);
 156  
 157          // Rule is defined.
 158          $this->assertTrue($customcompletion->is_defined('completionsubmit'));
 159  
 160          // Undefined rule.
 161          $this->assertFalse($customcompletion->is_defined('somerandomrule'));
 162      }
 163  
 164      /**
 165       * Data provider for test_get_available_custom_rules().
 166       *
 167       * @return array[]
 168       */
 169      public function get_available_custom_rules_provider(): array {
 170          return [
 171              'Completion submit available' => [
 172                  COMPLETION_ENABLED, ['completionsubmit']
 173              ],
 174              'Completion submit not available' => [
 175                  COMPLETION_DISABLED, []
 176              ],
 177          ];
 178      }
 179  
 180      /**
 181       * Test for get_available_custom_rules().
 182       *
 183       * @dataProvider get_available_custom_rules_provider
 184       * @param int $status
 185       * @param array $expected
 186       */
 187      public function test_get_available_custom_rules(int $status, array $expected) {
 188          $customdataval = [
 189              'customcompletionrules' => [
 190                  'completionsubmit' => $status
 191              ]
 192          ];
 193  
 194          // Build a mock cm_info instance.
 195          $mockcminfo = $this->getMockBuilder(cm_info::class)
 196              ->disableOriginalConstructor()
 197              ->onlyMethods(['__get'])
 198              ->getMock();
 199  
 200          // Mock the return of magic getter for the customdata attribute.
 201          $mockcminfo->expects($this->any())
 202              ->method('__get')
 203              ->with('customdata')
 204              ->willReturn($customdataval);
 205  
 206          $customcompletion = new custom_completion($mockcminfo, 1);
 207          $this->assertEquals($expected, $customcompletion->get_available_custom_rules());
 208      }
 209  }