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   * Unit tests for mod/workshop/lib.php.
  18   *
  19   * @package    mod_workshop
  20   * @copyright  2017 Simey Lameze <simey@moodle.com>
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   */
  23  defined('MOODLE_INTERNAL') || die();
  24  
  25  global $CFG;
  26  require_once($CFG->dirroot . '/mod/workshop/lib.php');
  27  
  28  /**
  29   * Unit tests for mod/workshop/lib.php.
  30   *
  31   * @copyright  2017 Simey Lameze <simey@moodle.com>
  32   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class mod_workshop_lib_testcase extends advanced_testcase {
  35  
  36      /**
  37       * Test calendar event provide action open.
  38       */
  39      public function test_workshop_core_calendar_provide_event_action_open() {
  40          $this->resetAfterTest();
  41          $this->setAdminUser();
  42  
  43          $now = time();
  44          $course = $this->getDataGenerator()->create_course();
  45          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
  46              'submissionstart' => $now - DAYSECS, 'submissionend' => $now + DAYSECS]);
  47          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
  48  
  49          $factory = new \core_calendar\action_factory();
  50          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
  51  
  52          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
  53          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
  54          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
  55          $this->assertEquals(1, $actionevent->get_item_count());
  56          $this->assertTrue($actionevent->is_actionable());
  57      }
  58  
  59      /**
  60       * Test calendar event provide action open for a non user.
  61       */
  62      public function test_workshop_core_calendar_provide_event_action_open_for_non_user() {
  63          global $CFG;
  64  
  65          $this->resetAfterTest();
  66          $this->setAdminUser();
  67  
  68          $now = time();
  69          $course = $this->getDataGenerator()->create_course();
  70          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
  71              'submissionstart' => $now - DAYSECS, 'submissionend' => $now + DAYSECS]);
  72          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
  73  
  74          // Now, log out.
  75          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
  76          $this->setUser();
  77  
  78          $factory = new \core_calendar\action_factory();
  79          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
  80  
  81          // Confirm the event is not shown at all.
  82          $this->assertNull($actionevent);
  83      }
  84  
  85      /**
  86       * Test calendar event provide action open when user id is provided.
  87       */
  88      public function test_workshop_core_calendar_provide_event_action_open_for_user() {
  89          global $CFG;
  90  
  91          $this->resetAfterTest();
  92          $this->setAdminUser();
  93  
  94          $now = time();
  95          $course = $this->getDataGenerator()->create_course();
  96          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
  97              'submissionstart' => $now - DAYSECS, 'submissionend' => $now + DAYSECS]);
  98          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
  99          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 100  
 101          // Now log out.
 102          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 103          $this->setUser();
 104  
 105          $factory = new \core_calendar\action_factory();
 106          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory, $student->id);
 107  
 108          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 109          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 110          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 111          $this->assertEquals(1, $actionevent->get_item_count());
 112          $this->assertTrue($actionevent->is_actionable());
 113      }
 114  
 115      /**
 116       * Test calendar event provide action closed.
 117       */
 118      public function test_workshop_core_calendar_provide_event_action_closed() {
 119          $this->resetAfterTest();
 120          $this->setAdminUser();
 121  
 122          $course = $this->getDataGenerator()->create_course();
 123          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id,
 124              'submissionend' => time() - DAYSECS));
 125          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 126  
 127          $factory = new \core_calendar\action_factory();
 128          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 129  
 130          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 131          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 132          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 133          $this->assertEquals(1, $actionevent->get_item_count());
 134          $this->assertTrue($actionevent->is_actionable());
 135      }
 136  
 137      /**
 138       * Test calendar event provide action closed for a non user.
 139       */
 140      public function test_workshop_core_calendar_provide_event_action_closed_for_non_user() {
 141          global $CFG;
 142  
 143          $this->resetAfterTest();
 144          $this->setAdminUser();
 145  
 146          $course = $this->getDataGenerator()->create_course();
 147          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id,
 148              'submissionend' => time() - DAYSECS));
 149          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 150  
 151          // Now, log out.
 152          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 153          $this->setUser();
 154  
 155          $factory = new \core_calendar\action_factory();
 156          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 157  
 158          // Confirm the event is not shown at all.
 159          $this->assertNull($actionevent);
 160      }
 161  
 162      /**
 163       * Test calendar event provide action closed when user id is provided.
 164       */
 165      public function test_workshop_core_calendar_provide_event_action_closed_for_user() {
 166          global $CFG;
 167  
 168          $this->resetAfterTest();
 169          $this->setAdminUser();
 170  
 171          $course = $this->getDataGenerator()->create_course();
 172          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id,
 173              'submissionend' => time() - DAYSECS));
 174          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 175          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 176  
 177          // Now log out.
 178          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 179          $this->setUser();
 180  
 181          $factory = new \core_calendar\action_factory();
 182          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory, $student->id);
 183  
 184          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 185          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 186          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 187          $this->assertEquals(1, $actionevent->get_item_count());
 188          $this->assertTrue($actionevent->is_actionable());
 189      }
 190  
 191      /**
 192       * Test calendar event action open in future.
 193       */
 194      public function test_workshop_core_calendar_provide_event_action_open_in_future() {
 195          $this->resetAfterTest();
 196          $this->setAdminUser();
 197  
 198          $course = $this->getDataGenerator()->create_course();
 199          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
 200              'submissionstart' => time() + DAYSECS]);
 201          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 202  
 203          $factory = new \core_calendar\action_factory();
 204          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 205  
 206          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 207          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 208          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 209          $this->assertEquals(1, $actionevent->get_item_count());
 210          $this->assertTrue($actionevent->is_actionable());
 211      }
 212  
 213      /**
 214       * Test calendar event action open in future for a non user.
 215       */
 216      public function test_workshop_core_calendar_provide_event_action_open_in_future_for_non_user() {
 217          global $CFG;
 218  
 219          $this->resetAfterTest();
 220          $this->setAdminUser();
 221  
 222          $course = $this->getDataGenerator()->create_course();
 223          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
 224              'submissionstart' => time() + DAYSECS]);
 225          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 226  
 227          // Now, log out.
 228          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 229          $this->setUser();
 230  
 231          $factory = new \core_calendar\action_factory();
 232          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 233  
 234          // Confirm the event is not shown at all.
 235          $this->assertNull($actionevent);
 236      }
 237  
 238      /**
 239       * Test calendar event action open in future when user id is provided.
 240       */
 241      public function test_workshop_core_calendar_provide_event_action_open_in_future_for_user() {
 242          global $CFG;
 243  
 244          $this->resetAfterTest();
 245          $this->setAdminUser();
 246  
 247          $course = $this->getDataGenerator()->create_course();
 248          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id,
 249              'submissionstart' => time() + DAYSECS]);
 250          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 251          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 252  
 253          // Now log out.
 254          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 255          $this->setUser();
 256  
 257          $factory = new \core_calendar\action_factory();
 258          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory, $student->id);
 259  
 260          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 261          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 262          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 263          $this->assertEquals(1, $actionevent->get_item_count());
 264          $this->assertTrue($actionevent->is_actionable());
 265      }
 266  
 267      /**
 268       * Test calendar event with no time specified.
 269       */
 270      public function test_workshop_core_calendar_provide_event_action_no_time_specified() {
 271          $this->resetAfterTest();
 272          $this->setAdminUser();
 273  
 274          $course = $this->getDataGenerator()->create_course();
 275          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id]);
 276          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 277  
 278          $factory = new \core_calendar\action_factory();
 279          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 280  
 281          $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
 282          $this->assertEquals(get_string('viewworkshopsummary', 'workshop'), $actionevent->get_name());
 283          $this->assertInstanceOf('moodle_url', $actionevent->get_url());
 284          $this->assertEquals(1, $actionevent->get_item_count());
 285          $this->assertTrue($actionevent->is_actionable());
 286      }
 287  
 288      /**
 289       * Test calendar event with no time specified for a non user.
 290       */
 291      public function test_workshop_core_calendar_provide_event_action_no_time_specified_for_non_user() {
 292          global $CFG;
 293  
 294          $this->resetAfterTest();
 295          $this->setAdminUser();
 296  
 297          $course = $this->getDataGenerator()->create_course();
 298          $workshop = $this->getDataGenerator()->create_module('workshop', ['course' => $course->id]);
 299          $event = $this->create_action_event($course->id, $workshop->id, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN);
 300  
 301          // Now, log out.
 302          $CFG->forcelogin = true; // We don't want to be logged in as guest, as guest users might still have some capabilities.
 303          $this->setUser();
 304  
 305          $factory = new \core_calendar\action_factory();
 306          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 307  
 308          // Confirm the event is not shown at all.
 309          $this->assertNull($actionevent);
 310      }
 311  
 312      public function test_workshop_core_calendar_provide_event_action_already_completed() {
 313          $this->resetAfterTest();
 314          set_config('enablecompletion', 1);
 315          $this->setAdminUser();
 316  
 317          // Create the activity.
 318          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 319          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id),
 320              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 321  
 322          // Get some additional data.
 323          $cm = get_coursemodule_from_instance('workshop', $workshop->id);
 324  
 325          // Create a calendar event.
 326          $event = $this->create_action_event($course->id, $workshop->id,
 327              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 328  
 329          // Mark the activity as completed.
 330          $completion = new completion_info($course);
 331          $completion->set_module_viewed($cm);
 332  
 333          // Create an action factory.
 334          $factory = new \core_calendar\action_factory();
 335  
 336          // Decorate action event.
 337          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory);
 338  
 339          // Ensure result was null.
 340          $this->assertNull($actionevent);
 341      }
 342  
 343      public function test_workshop_core_calendar_provide_event_action_already_completed_for_user() {
 344          $this->resetAfterTest();
 345          set_config('enablecompletion', 1);
 346          $this->setAdminUser();
 347  
 348          // Create the activity.
 349          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
 350          $workshop = $this->getDataGenerator()->create_module('workshop', array('course' => $course->id),
 351              array('completion' => 2, 'completionview' => 1, 'completionexpected' => time() + DAYSECS));
 352  
 353          // Enrol a student in the course.
 354          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 355  
 356          // Get some additional data.
 357          $cm = get_coursemodule_from_instance('workshop', $workshop->id);
 358  
 359          // Create a calendar event.
 360          $event = $this->create_action_event($course->id, $workshop->id,
 361              \core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED);
 362  
 363          // Mark the activity as completed for the student.
 364          $completion = new completion_info($course);
 365          $completion->set_module_viewed($cm, $student->id);
 366  
 367          // Create an action factory.
 368          $factory = new \core_calendar\action_factory();
 369  
 370          // Decorate action event for the student.
 371          $actionevent = mod_workshop_core_calendar_provide_event_action($event, $factory, $student->id);
 372  
 373          // Ensure result was null.
 374          $this->assertNull($actionevent);
 375      }
 376  
 377      /**
 378       * Creates an action event.
 379       *
 380       * @param int $courseid The course id.
 381       * @param int $instanceid The workshop id.
 382       * @param string $eventtype The event type. eg. WORKSHOP_EVENT_TYPE_OPEN.
 383       * @return bool|calendar_event
 384       */
 385      private function create_action_event($courseid, $instanceid, $eventtype) {
 386          $event = new stdClass();
 387          $event->name = 'Calendar event';
 388          $event->modulename = 'workshop';
 389          $event->courseid = $courseid;
 390          $event->instance = $instanceid;
 391          $event->type = CALENDAR_EVENT_TYPE_ACTION;
 392          $event->eventtype = $eventtype;
 393          $event->timestart = time();
 394  
 395          return calendar_event::create($event);
 396      }
 397  
 398      /**
 399       * Test check_updates_since callback.
 400       */
 401      public function test_check_updates_since() {
 402          global $DB;
 403  
 404          $this->resetAfterTest();
 405          $this->setAdminUser();
 406          $course = $this->getDataGenerator()->create_course();
 407  
 408          // Create user.
 409          $student = self::getDataGenerator()->create_user();
 410          $teacher = self::getDataGenerator()->create_user();
 411  
 412          // User enrolment.
 413          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
 414          $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
 415          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 416          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
 417  
 418          $this->setCurrentTimeStart();
 419          $record = array(
 420              'course' => $course->id,
 421              'custom' => 0,
 422              'feedback' => 1,
 423          );
 424          $workshop = $this->getDataGenerator()->create_module('workshop', $record);
 425          $cm = get_coursemodule_from_instance('workshop', $workshop->id, $course->id);
 426          $context = context_module::instance($cm->id);
 427          $cm = cm_info::create($cm);
 428  
 429          $this->setUser($student);
 430          // Check that upon creation, the updates are only about the new configuration created.
 431          $onehourago = time() - HOURSECS;
 432          $updates = workshop_check_updates_since($cm, $onehourago);
 433          foreach ($updates as $el => $val) {
 434              if ($el == 'configuration') {
 435                  $this->assertTrue($val->updated);
 436                  $this->assertTimeCurrent($val->timeupdated);
 437              } else {
 438                  $this->assertFalse($val->updated);
 439              }
 440          }
 441  
 442          // Set up a generator to create content.
 443          $generator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 444          // Submission.
 445          $submissionid = $generator->create_submission($workshop->id, $student->id, array(
 446              'title' => 'My custom title',
 447          ));
 448          // Now assessment.
 449          $assessmentid = $generator->create_assessment($submissionid, $student->id, array(
 450              'weight' => 3,
 451              'grade' => 95.00000,
 452          ));
 453          // Add files to one editor file area.
 454          $fs = get_file_storage();
 455          $filerecordinline = array(
 456              'contextid' => $context->id,
 457              'component' => 'mod_workshop',
 458              'filearea'  => 'instructauthors',
 459              'itemid'    => 0,
 460              'filepath'  => '/',
 461              'filename'  => 'image.png',
 462          );
 463          $instructauthorsfile = $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
 464  
 465          $updates = workshop_check_updates_since($cm, $onehourago);
 466          $this->assertTrue($updates->submissions->updated);
 467          $this->assertCount(1, $updates->submissions->itemids);
 468          $this->assertEquals($submissionid, $updates->submissions->itemids[0]);
 469          $this->assertTrue($updates->assessments->updated);
 470          $this->assertCount(1, $updates->assessments->itemids);
 471          $this->assertEquals($assessmentid, $updates->assessments->itemids[0]);
 472          $this->assertTrue($updates->instructauthorsfiles->updated);
 473          $this->assertCount(1, $updates->instructauthorsfiles->itemids);
 474          $this->assertEquals($instructauthorsfile->get_id(), $updates->instructauthorsfiles->itemids[0]);
 475  
 476          // Check I see the user updates as teacher.
 477          $this->setUser($teacher);
 478          $updates = workshop_check_updates_since($cm, $onehourago);
 479          $this->assertTrue($updates->usersubmissions->updated);
 480          $this->assertCount(1, $updates->usersubmissions->itemids);
 481          $this->assertEquals($submissionid, $updates->usersubmissions->itemids[0]);
 482          $this->assertTrue($updates->userassessments->updated);
 483          $this->assertCount(1, $updates->userassessments->itemids);
 484          $this->assertEquals($assessmentid, $updates->userassessments->itemids[0]);
 485          $this->assertTrue($updates->instructauthorsfiles->updated);
 486          $this->assertCount(1, $updates->instructauthorsfiles->itemids);
 487          $this->assertEquals($instructauthorsfile->get_id(), $updates->instructauthorsfiles->itemids[0]);
 488  
 489          // The teacher didn't do anything.
 490          $this->assertFalse($updates->submissions->updated);
 491          $this->assertFalse($updates->assessments->updated);
 492      }
 493  
 494      /**
 495       * An unknown event type should not have any limits
 496       */
 497      public function test_mod_workshop_core_calendar_get_valid_event_timestart_range_unknown_event() {
 498          global $CFG;
 499          require_once($CFG->dirroot . "/calendar/lib.php");
 500  
 501          $this->resetAfterTest(true);
 502          $this->setAdminUser();
 503  
 504          $course = $this->getDataGenerator()->create_course();
 505          $timestart = time();
 506          $timeend = $timestart + DAYSECS;
 507          $workshop = new \stdClass();
 508          $workshop->submissionstart = $timestart;
 509          $workshop->submissionend = $timeend;
 510          $workshop->assessmentstart = 0;
 511          $workshop->assessmentend = 0;
 512  
 513          // Create a valid event.
 514          $event = new \calendar_event([
 515              'name' => 'Test event',
 516              'description' => '',
 517              'format' => 1,
 518              'courseid' => $course->id,
 519              'groupid' => 0,
 520              'userid' => 2,
 521              'modulename' => 'workshop',
 522              'instance' => 1,
 523              'eventtype' => WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE . "SOMETHING ELSE",
 524              'timestart' => 1,
 525              'timeduration' => 86400,
 526              'visible' => 1
 527          ]);
 528          list ($min, $max) = mod_workshop_core_calendar_get_valid_event_timestart_range($event, $workshop);
 529          $this->assertNull($min);
 530          $this->assertNull($max);
 531      }
 532  
 533      /**
 534       * Provider for test_mod_workshop_core_calendar_get_valid_event_timestart_range.
 535       *
 536       * @return array of (submissionstart, submissionend, assessmentstart, assessmentend, eventtype, expectedmin, expectedmax)
 537       */
 538      public function mod_workshop_core_calendar_get_valid_event_timestart_range_due_no_limit_provider() {
 539          $submissionstart = time() + DAYSECS;
 540          $submissionend = $submissionstart + DAYSECS;
 541          $assessmentstart = $submissionend + DAYSECS;
 542          $assessmentend = $assessmentstart + DAYSECS;
 543  
 544          return [
 545              'Only with submissionstart' => [$submissionstart, 0, 0, 0, WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, null, null],
 546              'Only with submissionend' => [0, $submissionend, 0, 0, WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, null, null],
 547              'Only with assessmentstart' => [0, 0, $assessmentstart, 0, WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, null, null],
 548              'Only with assessmentend' => [0, 0, 0, $assessmentend, WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, null, null],
 549  
 550              'Move submissionstart when with submissionend' => [$submissionstart, $submissionend, 0, 0,
 551                      WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, null, $submissionend - 1],
 552              'Move submissionend when with submissionstart' => [$submissionstart, $submissionend, 0, 0,
 553                      WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, $submissionstart + 1, null],
 554              'Move assessmentstart when with assessmentend' => [0, 0, $assessmentstart, $assessmentend,
 555                      WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, null, $assessmentend - 1],
 556              'Move assessmentend when with assessmentstart' => [0, 0, $assessmentstart, $assessmentend,
 557                      WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, $assessmentstart + 1, null],
 558  
 559              'Move submissionstart when with assessmentstart' => [$submissionstart, 0, $assessmentstart, 0,
 560                      WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, null, $assessmentstart],
 561              'Move submissionstart when with assessmentend' => [$submissionstart, 0, 0, $assessmentend,
 562                      WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, null, $assessmentend],
 563              'Move submissionend when with assessmentstart' => [0, $submissionend, $assessmentstart, 0,
 564                      WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, null, $assessmentstart],
 565              'Move submissionend when with assessmentend' => [0, $submissionend, 0, $assessmentend,
 566                      WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, null, $assessmentend],
 567  
 568              'Move assessmentstart when with submissionstart' => [$submissionstart, 0, $assessmentstart, 0,
 569                      WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, $submissionstart, null],
 570              'Move assessmentstart when with submissionend' => [0, $submissionend, $assessmentstart, 0,
 571                      WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, $submissionend, null],
 572              'Move assessmentend when with submissionstart' => [$submissionstart, 0, 0, $assessmentend,
 573                      WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, $submissionstart, null],
 574              'Move assessmentend when with submissionend' => [0, $submissionend, 0, $assessmentend,
 575                      WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, $submissionend, null],
 576  
 577              'Move submissionstart when with others' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 578                      WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, null, $submissionend - 1],
 579              'Move submissionend when with others' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 580                      WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, $submissionstart + 1, $assessmentstart],
 581              'Move assessmentstart when with others' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 582                      WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, $submissionend, $assessmentend - 1],
 583              'Move assessmentend when with others' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 584                      WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, $assessmentstart + 1, null],
 585          ];
 586      }
 587  
 588      /**
 589       * Tests mod_workshop_core_calendar_get_valid_event_timestart_range in various settings.
 590       *
 591       * @dataProvider mod_workshop_core_calendar_get_valid_event_timestart_range_due_no_limit_provider
 592       *
 593       * @param int $submissionstart  The start of the submission phase
 594       * @param int $submissionend    The end of the submission phase
 595       * @param int $assessmentstart  The start of the assessment phase
 596       * @param int $assessmentend    The end of the assessment phase
 597       * @param string $eventtype     The type if the event
 598       * @param int|null $expectedmin The expected value for min of the valid event range
 599       * @param int|null $expectedmax The expected value for max of the valid event range
 600       */
 601      public function test_mod_workshop_core_calendar_get_valid_event_timestart_range($submissionstart, $submissionend,
 602              $assessmentstart, $assessmentend, $eventtype, $expectedmin, $expectedmax) {
 603  
 604          global $CFG;
 605          require_once($CFG->dirroot . '/calendar/lib.php');
 606  
 607          $this->resetAfterTest(true);
 608          $this->setAdminUser();
 609  
 610          $course = $this->getDataGenerator()->create_course();
 611          $workshop = new \stdClass();
 612          $workshop->submissionstart = $submissionstart;
 613          $workshop->submissionend = $submissionend;
 614          $workshop->assessmentstart = $assessmentstart;
 615          $workshop->assessmentend = $assessmentend;
 616  
 617          // Create a valid event.
 618          $event = new \calendar_event([
 619              'name' => 'Test event',
 620              'description' => '',
 621              'format' => 1,
 622              'courseid' => $course->id,
 623              'groupid' => 0,
 624              'userid' => 2,
 625              'modulename' => 'workshop',
 626              'instance' => 1,
 627              'eventtype' => $eventtype,
 628              'timestart' => 1,
 629              'timeduration' => 86400,
 630              'visible' => 1
 631          ]);
 632          list($min, $max) = mod_workshop_core_calendar_get_valid_event_timestart_range($event, $workshop);
 633  
 634          $this->assertSame($expectedmin, is_array($min) ? $min[0] : $min);
 635          $this->assertSame($expectedmax, is_array($max) ? $max[0] : $max);
 636      }
 637  
 638      /**
 639       * An unknown event type should not change the workshop instance.
 640       */
 641      public function test_mod_workshop_core_calendar_event_timestart_updated_unknown_event() {
 642          global $CFG, $DB;
 643          require_once($CFG->dirroot . "/calendar/lib.php");
 644  
 645          $this->resetAfterTest(true);
 646          $this->setAdminUser();
 647  
 648          $generator = $this->getDataGenerator();
 649          $course = $generator->create_course();
 650  
 651          $workshopgenerator = $generator->get_plugin_generator('mod_workshop');
 652          $submissionstart = time() + DAYSECS;
 653          $submissionend = $submissionstart + DAYSECS;
 654          $assessmentstart = $submissionend + DAYSECS;
 655          $assessmentend = $assessmentstart + DAYSECS;
 656          $workshop = $workshopgenerator->create_instance(['course' => $course->id]);
 657          $workshop->submissionstart = $submissionstart;
 658          $workshop->submissionend = $submissionend;
 659          $workshop->assessmentstart = $assessmentstart;
 660          $workshop->assessmentend = $assessmentend;
 661          $DB->update_record('workshop', $workshop);
 662  
 663          // Create a valid event.
 664          $event = new \calendar_event([
 665              'name' => 'Test event',
 666              'description' => '',
 667              'format' => 1,
 668              'courseid' => $course->id,
 669              'groupid' => 0,
 670              'userid' => 2,
 671              'modulename' => 'workshop',
 672              'instance' => $workshop->id,
 673              'eventtype' => WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE . "SOMETHING ELSE",
 674              'timestart' => 1,
 675              'timeduration' => 86400,
 676              'visible' => 1
 677          ]);
 678  
 679          mod_workshop_core_calendar_event_timestart_updated($event, $workshop);
 680  
 681          $workshop = $DB->get_record('workshop', ['id' => $workshop->id]);
 682          $this->assertEquals($submissionstart, $workshop->submissionstart);
 683          $this->assertEquals($submissionend, $workshop->submissionend);
 684          $this->assertEquals($assessmentstart, $workshop->assessmentstart);
 685          $this->assertEquals($assessmentend, $workshop->assessmentend);
 686      }
 687  
 688      /**
 689       * Provider for test_mod_workshop_core_calendar_event_timestart_updated.
 690       *
 691       * @return array of (submissionstart, submissionend, assessmentstart, assessmentend, eventtype, fieldtoupdate, newtime)
 692       */
 693      public function mod_workshop_core_calendar_event_timestart_updated_provider() {
 694          $submissionstart = time() + DAYSECS;
 695          $submissionend = $submissionstart + DAYSECS;
 696          $assessmentstart = $submissionend + DAYSECS;
 697          $assessmentend = $assessmentstart + DAYSECS;
 698  
 699          return [
 700              'Move submissionstart' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 701                      WORKSHOP_EVENT_TYPE_SUBMISSION_OPEN, 'submissionstart', $submissionstart + 50],
 702              'Move submissionend' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 703                      WORKSHOP_EVENT_TYPE_SUBMISSION_CLOSE, 'submissionend', $submissionend + 50],
 704              'Move assessmentstart' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 705                      WORKSHOP_EVENT_TYPE_ASSESSMENT_OPEN, 'assessmentstart', $assessmentstart + 50],
 706              'Move assessmentend' => [$submissionstart, $submissionend, $assessmentstart, $assessmentend,
 707                      WORKSHOP_EVENT_TYPE_ASSESSMENT_CLOSE, 'assessmentend', $assessmentend + 50],
 708          ];
 709      }
 710  
 711      /**
 712       * Due date events should update the workshop due date.
 713       *
 714       * @dataProvider mod_workshop_core_calendar_event_timestart_updated_provider
 715       *
 716       * @param int $submissionstart  The start of the submission phase
 717       * @param int $submissionend    The end of the submission phase
 718       * @param int $assessmentstart  The start of the assessment phase
 719       * @param int $assessmentend    The end of the assessment phase
 720       * @param string $eventtype     The type if the event
 721       * @param string $fieldtoupdate The field that is supposed to be updated.
 722       *                              Either of 'submissionstart', 'submissionend', 'assessmentstart' or 'assessmentend'.
 723       * @param int $newtime          The new value for the $fieldtoupdate
 724       */
 725      public function test_mod_workshop_core_calendar_event_timestart_updated($submissionstart, $submissionend, $assessmentstart,
 726              $assessmentend, $eventtype, $fieldtoupdate, $newtime) {
 727          global $CFG, $DB;
 728          require_once($CFG->dirroot . "/calendar/lib.php");
 729  
 730          $this->resetAfterTest(true);
 731          $this->setAdminUser();
 732  
 733          $generator = $this->getDataGenerator();
 734          $course = $generator->create_course();
 735  
 736          $workshopgenerator = $generator->get_plugin_generator('mod_workshop');
 737          $workshop = $workshopgenerator->create_instance(['course' => $course->id]);
 738          $workshop->submissionstart = $submissionstart;
 739          $workshop->submissionend = $submissionend;
 740          $workshop->assessmentstart = $assessmentstart;
 741          $workshop->assessmentend = $assessmentend;
 742          $DB->update_record('workshop', $workshop);
 743  
 744          // Create a valid event.
 745          $event = new \calendar_event([
 746              'name' => 'Test event',
 747              'description' => '',
 748              'format' => 1,
 749              'courseid' => $course->id,
 750              'groupid' => 0,
 751              'userid' => 2,
 752              'modulename' => 'workshop',
 753              'instance' => $workshop->id,
 754              'eventtype' => $eventtype,
 755              'timestart' => $newtime,
 756              'timeduration' => 86400,
 757              'visible' => 1
 758          ]);
 759          mod_workshop_core_calendar_event_timestart_updated($event, $workshop);
 760  
 761          $$fieldtoupdate = $newtime;
 762  
 763          $workshop = $DB->get_record('workshop', ['id' => $workshop->id]);
 764          $this->assertEquals($submissionstart, $workshop->submissionstart);
 765          $this->assertEquals($submissionend, $workshop->submissionend);
 766          $this->assertEquals($assessmentstart, $workshop->assessmentstart);
 767          $this->assertEquals($assessmentend, $workshop->assessmentend);
 768      }
 769  }