Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

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

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

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