Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

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

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 401 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                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionscorerequired' => 1,
  85                      'completionstatusrequired' => [2 => 'passed']],
  86                  ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionscorerequired' => 1,
  87                      'completionstatusrequired' => 2]],
  88              'scorm-2' => ['scorm', ['completion' => COMPLETION_TRACKING_MANUAL]],
  89              'survey-1' => ['survey', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1]],
  90              'survey-2' => ['survey', ['completion' => COMPLETION_TRACKING_MANUAL]],
  91              'url-1' => ['url', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  92              'url-2' => ['url', ['completion' => COMPLETION_TRACKING_MANUAL]],
  93              'wiki-1' => ['wiki', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  94              'wiki-2' => ['wiki', ['completion' => COMPLETION_TRACKING_MANUAL]],
  95              'workshop-1' => ['workshop', ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1]],
  96              'workshop-2' => ['workshop', ['completion' => COMPLETION_TRACKING_MANUAL]],
  97          ];
  98      }
  99  
 100      /**
 101       * Creates an instance of bulk edit completion form for one activity, validates and saves it
 102       *
 103       * @dataProvider bulk_form_submit_single_provider
 104       * @param string $modname
 105       * @param array $submitdata data to use in mock form submit
 106       * @param array|null $validatedata data to validate the
 107       */
 108      public function test_bulk_form_submit_single($modname, $submitdata, $validatedata = null) {
 109          global $DB;
 110  
 111          if ($validatedata === null) {
 112              $validatedata = $submitdata;
 113          }
 114  
 115          $this->resetAfterTest();
 116          $this->setAdminUser();
 117          list($course, $cms) = $this->create_course_and_modules([$modname]);
 118  
 119          // Submit the bulk completion form with the provided data and make sure it returns the same data.
 120          core_completion_bulkedit_form::mock_submit(['id' => $course->id, 'cmid' => array_keys($cms)] + $submitdata, []);
 121          $form = new core_completion_bulkedit_form(null, ['cms' => $cms]);
 122          $this->assertTrue($form->is_validated());
 123          $data = $form->get_data();
 124          foreach ($validatedata as $key => $value) {
 125              $this->assertEquals($value, $data->$key);
 126          }
 127  
 128          // Apply completion rules to the modules.
 129          $manager = new manager($course->id);
 130          $manager->apply_completion($data, $form->has_custom_completion_rules());
 131  
 132          // Make sure either course_modules or instance table was respectfully updated.
 133          $cm = reset($cms);
 134          $cmrec = $DB->get_record('course_modules', ['id' => $cm->id]);
 135          $instancerec = $DB->get_record($modname, ['id' => $cm->instance]);
 136          foreach ($validatedata as $key => $value) {
 137              if (property_exists($cmrec, $key)) {
 138                  $this->assertEquals($value, $cmrec->$key);
 139              } else {
 140                  $this->assertEquals($value, $instancerec->$key);
 141              }
 142          }
 143      }
 144  
 145      /**
 146       * Creates a course and the number of modules
 147       * @param array $modulenames
 148       * @return array array of two elements - course and list of cm_info objects
 149       */
 150      protected function create_course_and_modules($modulenames) {
 151          global $CFG, $PAGE;
 152  
 153          $CFG->enablecompletion = true;
 154          $course = $this->getDataGenerator()->create_course(['enablecompletion' => 1], ['createsections' => true]);
 155          $PAGE->set_course($course);
 156  
 157          $cmids = [];
 158          foreach ($modulenames as $modname) {
 159              $module = $this->getDataGenerator()->create_module($modname, ['course' => $course->id]);
 160              $cmids[] = $module->cmid;
 161          }
 162          $modinfo = get_fast_modinfo($course);
 163          $cms = [];
 164          foreach ($cmids as $cmid) {
 165              $cms[$cmid] = $modinfo->get_cm($cmid);
 166          }
 167          return [$course, $cms];
 168      }
 169  
 170      /**
 171       * Provider for test_bulk_form_submit_multiple
 172       * @return array
 173       */
 174      public function bulk_form_submit_multiple_provider() {
 175          return [
 176              'Several modules with the same module type (choice)' => [
 177                  [
 178                      'modulenames' => ['choice', 'choice', 'choice'],
 179                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1],
 180                      'validatedata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionsubmit' => 1],
 181                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC],
 182                      'instancedata' => [['completionsubmit' => 1], ['completionsubmit' => 1], ['completionsubmit' => 1]]
 183                  ]
 184              ],
 185              'Several modules with different module type' => [
 186                  [
 187                      'modulenames' => ['choice', 'forum'],
 188                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 189                      'validatedata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 190                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC],
 191                      'instancedata' => null
 192                  ]
 193              ],
 194              'Setting manual completion (completionview shoud be ignored)' => [
 195                  [
 196                      'modulenames' => ['scorm', 'forum', 'label', 'assign'],
 197                      'submitdata' => ['completion' => COMPLETION_TRACKING_MANUAL, 'completionview' => 1],
 198                      'validatedata' => [],
 199                      'cmdata' => ['completion' => COMPLETION_TRACKING_MANUAL, 'completionview' => 0],
 200                      'instancedata' => null
 201                  ]
 202              ],
 203              'If at least one module does not support completionsubmit it can\'t be set' => [
 204                  [
 205                      'modulenames' => ['survey', 'wiki'],
 206                      'submitdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1, 'completionsubmit' => 1],
 207                      'validatedata' => [],
 208                      'cmdata' => ['completion' => COMPLETION_TRACKING_AUTOMATIC, 'completionview' => 1],
 209                      'instancedata' => [['completionsubmit' => 0], []]
 210                  ]
 211              ]
 212          ];
 213      }
 214  
 215      /**
 216       * Use bulk completion edit for updating multiple modules
 217       *
 218       * @dataProvider bulk_form_submit_multiple_provider
 219       * @param array $providerdata
 220       */
 221      public function test_bulk_form_submit_multiple($providerdata) {
 222          global $DB;
 223  
 224          $modulenames = $providerdata['modulenames'];
 225          $submitdata = $providerdata['submitdata'];
 226          $validatedata = $providerdata['validatedata'];
 227          $cmdata = $providerdata['cmdata'];
 228          $instancedata = $providerdata['instancedata'];
 229  
 230          $this->resetAfterTest();
 231          $this->setAdminUser();
 232          list($course, $cms) = $this->create_course_and_modules($modulenames);
 233  
 234          // Submit the bulk completion form with the provided data and make sure it returns the same data.
 235          core_completion_bulkedit_form::mock_submit(['id' => $course->id, 'cmid' => array_keys($cms)] + $submitdata, []);
 236          $form = new core_completion_bulkedit_form(null, ['cms' => $cms]);
 237          $this->assertTrue($form->is_validated());
 238          $data = $form->get_data();
 239          foreach ($validatedata as $key => $value) {
 240              $this->assertEquals($value, $data->$key);
 241          }
 242  
 243          // Apply completion rules to the modules.
 244          $manager = new manager($course->id);
 245          $manager->apply_completion($data, $form->has_custom_completion_rules());
 246  
 247          // Make sure either course_modules or instance table was respectfully updated.
 248          $cnt = 0;
 249          foreach ($cms as $cm) {
 250              $cmrec = $DB->get_record('course_modules', ['id' => $cm->id]);
 251              $instancerec = $DB->get_record($cm->modname, ['id' => $cm->instance]);
 252              foreach ($cmdata as $key => $value) {
 253                  $this->assertEquals($value, $cmrec->$key, 'Error asserting that value for the field ' . $key.' ' .
 254                      $cmrec->$key . ' matches expected value ' . $value);
 255              }
 256              if ($instancedata) {
 257                  foreach ($instancedata[$cnt] as $key => $value) {
 258                      $this->assertEquals($value, $instancerec->$key, 'Error asserting that value for the field ' . $key . ' '.
 259                          $instancerec->$key . ' matches expected value ' . $value);
 260                  }
 261              }
 262              $cnt++;
 263          }
 264      }
 265  }