Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 39 and 311]

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