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.

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core_completion;
  18  
  19  use core_completion_bulkedit_form;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  global $CFG;
  24  require_once($CFG->libdir . '/completionlib.php');
  25  
  26  /**
  27   * External completion functions unit tests
  28   *
  29   * @package    core_completion
  30   * @copyright  2017 Marina Glancy
  31   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  32   */
  33  class bulk_update_test extends \advanced_testcase {
  34  
  35      /**
  36       * Provider for test_bulk_form_submit_single
  37       * @return array
  38       */
  39      public function bulk_form_submit_single_provider() {
  40          return [
  41              'assign-1' => ['assign', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1]],
  42              'assign-2' => ['assign', ['completion' => COMPLETION_TRACKING_MANUAL]],
  43              'book-1' => ['book', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  44              'book-2' => ['book', ['completion' => COMPLETION_TRACKING_MANUAL]],
  45              'chat-1' => ['chat', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  46              'chat-2' => ['chat', ['completion' => COMPLETION_TRACKING_MANUAL]],
  47              'choice-1' => ['choice', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1]],
  48              'choice-2' => ['choice', ['completion' => COMPLETION_TRACKING_MANUAL]],
  49              'data-1' => ['data', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  50              'data-2' => ['data', ['completion' => COMPLETION_TRACKING_MANUAL]],
  51              'data-3' => ['data',
  52                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionentries' => 3,
  53                      'completionentriesenabled' => 1],
  54                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionentries' => 3]],
  55              'feedback-1' => ['feedback', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 0,
  56                  'completionsubmit' => 1]],
  57              'feedback-2' => ['feedback', ['completion' => COMPLETION_TRACKING_MANUAL]],
  58              'folder-1' => ['folder', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  59              'folder-2' => ['folder', ['completion' => COMPLETION_TRACKING_MANUAL]],
  60              'forum-1' => ['forum',
  61                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completiondiscussions' => 1,
  62                      'completiondiscussionsenabled' => 1],
  63                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completiondiscussions' => 1]],
  64              'forum-2' => ['forum', ['completion' => COMPLETION_TRACKING_MANUAL]],
  65              'glossary-1' => ['glossary',
  66                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionentries' => 3,
  67                      'completionentriesenabled' => 1],
  68                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionentries' => 3]],
  69              'glossary-2' => ['glossary', ['completion' => COMPLETION_TRACKING_MANUAL]],
  70              'imscp-1' => ['imscp', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  71              'imscp-2' => ['imscp', ['completion' => COMPLETION_TRACKING_MANUAL]],
  72              'label-1' => ['label', ['completion' => COMPLETION_TRACKING_MANUAL]],
  73              'lesson-1' => ['lesson', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionendreached' => 1]],
  74              'lesson-2' => ['lesson', ['completion' => COMPLETION_TRACKING_MANUAL]],
  75              'lti-1' => ['lti', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  76              'lti-2' => ['lti', ['completion' => COMPLETION_TRACKING_MANUAL]],
  77              'page-1' => ['page', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  78              'page-2' => ['page', ['completion' => COMPLETION_TRACKING_MANUAL]],
  79              'quiz-1' => ['quiz', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionpassgrade' => 1]],
  80              'quiz-2' => ['quiz', ['completion' => COMPLETION_TRACKING_MANUAL]],
  81              'resource-1' => ['resource', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  82              'resource-2' => ['resource', ['completion' => COMPLETION_TRACKING_MANUAL]],
  83              'scorm-1' => ['scorm',
  84                  [
  85                      'completion' => COMPLETION_TRACKING_AUTOMATIC,
  86                      'completionscoreenabled' => 1,
  87                      'completionscorerequired' => 1,
  88                      'completionstatusrequired' => [2 => 'passed'],
  89                  ],
  90                  [
  91                      'completion' => COMPLETION_TRACKING_AUTOMATIC,
  92                      'completionscorerequired' => 1,
  93                      'completionstatusrequired' => 2,
  94                  ],
  95              ],
  96              'scorm-2' => ['scorm', ['completion' => COMPLETION_TRACKING_MANUAL]],
  97              'survey-1' => ['survey', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1]],
  98              'survey-2' => ['survey', ['completion' => COMPLETION_TRACKING_MANUAL]],
  99              'url-1' => ['url', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
 100              'url-2' => ['url', ['completion' => COMPLETION_TRACKING_MANUAL]],
 101              'wiki-1' => ['wiki', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
 102              'wiki-2' => ['wiki', ['completion' => COMPLETION_TRACKING_MANUAL]],
 103              'workshop-1' => ['workshop', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
 104              'workshop-2' => ['workshop', ['completion' => COMPLETION_TRACKING_MANUAL]],
 105          ];
 106      }
 107  
 108      /**
 109       * Creates an instance of bulk edit completion form for one activity, validates and saves it
 110       *
 111       * @dataProvider bulk_form_submit_single_provider
 112       * @param string $modname
 113       * @param array $submitdata data to use in mock form submit
 114       * @param array|null $validatedata data to validate the
 115       */
 116      public function test_bulk_form_submit_single($modname, $submitdata, $validatedata = null) {
 117          global $DB;
 118  
 119          if ($validatedata === null) {
 120              $validatedata = $submitdata;
 121          }
 122  
 123          $this->resetAfterTest();
 124          $this->setAdminUser();
 125          list($course, $cms) = $this->create_course_and_modules([$modname]);
 126  
 127          // Submit the bulk completion form with the provided data and make sure it returns the same data.
 128          core_completion_bulkedit_form::mock_submit(['id' => $course->id, 'cmid' => array_keys($cms)] + $submitdata, []);
 129          $form = new core_completion_bulkedit_form(null, ['cms' => $cms]);
 130          $this->assertTrue($form->is_validated());
 131          $data = $form->get_data();
 132          foreach ($validatedata as $key => $value) {
 133              $this->assertEquals($value, $data->$key);
 134          }
 135  
 136          // Apply completion rules to the modules.
 137          $manager = new manager($course->id);
 138          $manager->apply_completion($data, $form->has_custom_completion_rules());
 139  
 140          // Make sure either course_modules or instance table was respectfully updated.
 141          $cm = reset($cms);
 142          $cmrec = $DB->get_record('course_modules', ['id' => $cm->id]);
 143          $instancerec = $DB->get_record($modname, ['id' => $cm->instance]);
 144          foreach ($validatedata as $key => $value) {
 145              if (property_exists($cmrec, $key)) {
 146                  $this->assertEquals($value, $cmrec->$key);
 147              } else {
 148                  $this->assertEquals($value, $instancerec->$key);
 149              }
 150          }
 151      }
 152  
 153      /**
 154       * Creates a course and the number of modules
 155       * @param array $modulenames
 156       * @return array array of two elements - course and list of cm_info objects
 157       */
 158      protected function create_course_and_modules($modulenames) {
 159          global $CFG, $PAGE;
 160  
 161          $CFG->enablecompletion = true;
 162          $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1], ['createsections' => true]);
 163          $PAGE->set_course($course);
 164  
 165          $cmids = [];
 166          foreach ($modulenames as $modname) {
 167              $module = $this->getDataGenerator()->create_module($modname, ['course' => $course->id]);
 168              $cmids[] = $module->cmid;
 169          }
 170          $modinfo = get_fast_modinfo($course);
 171          $cms = [];
 172          foreach ($cmids as $cmid) {
 173              $cms[$cmid] = $modinfo->get_cm($cmid);
 174          }
 175          return [$course, $cms];
 176      }
 177  
 178      /**
 179       * Provider for test_bulk_form_submit_multiple
 180       * @return array
 181       */
 182      public function bulk_form_submit_multiple_provider() {
 183          return [
 184              'Several modules with the same module type (choice)' => [
 185                  [
 186                      'modulenames' => ['choice', 'choice', 'choice'],
 187                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1],
 188                      'validatedata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1],
 189                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC],
 190                      'instancedata' => [['completionsubmit' => 1], ['completionsubmit' => 1], ['completionsubmit' => 1]]
 191                  ]
 192              ],
 193              'Several modules with different module type' => [
 194                  [
 195                      'modulenames' => ['choice', 'forum'],
 196                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 197                      'validatedata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 198                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC],
 199                      'instancedata' => null
 200                  ]
 201              ],
 202              'Setting manual completion (completionview shoud be ignored)' => [
 203                  [
 204                      'modulenames' => ['scorm', 'forum', 'label', 'assign'],
 205                      'submitdata' => ['completion' => COMPLETION_TRACKING_MANUAL, 'completionview' => 1],
 206                      'validatedata' => [],
 207                      'cmdata' => ['completion' => COMPLETION_TRACKING_MANUAL, 'completionview' => 0],
 208                      'instancedata' => null
 209                  ]
 210              ],
 211              'If at least one module does not support completionsubmit it can\'t be set' => [
 212                  [
 213                      'modulenames' => ['survey', 'wiki'],
 214                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionsubmit' => 1],
 215                      'validatedata' => [],
 216                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 217                      'instancedata' => [['completionsubmit' => 0], []]
 218                  ]
 219              ]
 220          ];
 221      }
 222  
 223      /**
 224       * Use bulk completion edit for updating multiple modules
 225       *
 226       * @dataProvider bulk_form_submit_multiple_provider
 227       * @param array $providerdata
 228       */
 229      public function test_bulk_form_submit_multiple($providerdata) {
 230          global $DB;
 231  
 232          $modulenames = $providerdata['modulenames'];
 233          $submitdata = $providerdata['submitdata'];
 234          $validatedata = $providerdata['validatedata'];
 235          $cmdata = $providerdata['cmdata'];
 236          $instancedata = $providerdata['instancedata'];
 237  
 238          $this->resetAfterTest();
 239          $this->setAdminUser();
 240          list($course, $cms) = $this->create_course_and_modules($modulenames);
 241  
 242          // Submit the bulk completion form with the provided data and make sure it returns the same data.
 243          core_completion_bulkedit_form::mock_submit(['id' => $course->id, 'cmid' => array_keys($cms)] + $submitdata, []);
 244          $form = new core_completion_bulkedit_form(null, ['cms' => $cms]);
 245          $this->assertTrue($form->is_validated());
 246          $data = $form->get_data();
 247          foreach ($validatedata as $key => $value) {
 248              $this->assertEquals($value, $data->$key);
 249          }
 250  
 251          // Apply completion rules to the modules.
 252          $manager = new manager($course->id);
 253          $manager->apply_completion($data, $form->has_custom_completion_rules());
 254  
 255          // Make sure either course_modules or instance table was respectfully updated.
 256          $cnt = 0;
 257          foreach ($cms as $cm) {
 258              $cmrec = $DB->get_record('course_modules', ['id' => $cm->id]);
 259              $instancerec = $DB->get_record($cm->modname, ['id' => $cm->instance]);
 260              foreach ($cmdata as $key => $value) {
 261                  $this->assertEquals($value, $cmrec->$key, 'Error asserting that value for the field ' . $key.' ' .
 262                      $cmrec->$key . ' matches expected value ' . $value);
 263              }
 264              if ($instancedata) {
 265                  foreach ($instancedata[$cnt] as $key => $value) {
 266                      $this->assertEquals($value, $instancerec->$key, 'Error asserting that value for the field ' . $key . ' '.
 267                          $instancerec->$key . ' matches expected value ' . $value);
 268                  }
 269              }
 270              $cnt++;
 271          }
 272      }
 273  }