MDL-63660 tool_dataprivacy: Increase expected export file size
[moodle.git] / mod / scorm / tests / lib_test.php
blob173e87923d9cdb85ade385046ebf6ae55c4d25b1
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.
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/>.
17 /**
18 * SCORM module library functions tests
20 * @package mod_scorm
21 * @category test
22 * @copyright 2015 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @since Moodle 3.0
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
31 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32 require_once($CFG->dirroot . '/mod/scorm/lib.php');
34 /**
35 * SCORM module library functions tests
37 * @package mod_scorm
38 * @category test
39 * @copyright 2015 Juan Leyva <juan@moodle.com>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 * @since Moodle 3.0
43 class mod_scorm_lib_testcase extends externallib_advanced_testcase {
45 /**
46 * Set up for every test
48 public function setUp() {
49 global $DB;
50 $this->resetAfterTest();
51 $this->setAdminUser();
53 // Setup test data.
54 $this->course = $this->getDataGenerator()->create_course();
55 $this->scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $this->course->id));
56 $this->context = context_module::instance($this->scorm->cmid);
57 $this->cm = get_coursemodule_from_instance('scorm', $this->scorm->id);
59 // Create users.
60 $this->student = self::getDataGenerator()->create_user();
61 $this->teacher = self::getDataGenerator()->create_user();
63 // Users enrolments.
64 $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
65 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
66 $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
67 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
70 /** Test scorm_check_mode
72 * @return void
74 public function test_scorm_check_mode() {
75 global $CFG;
77 $newattempt = 'on';
78 $attempt = 1;
79 $mode = 'normal';
80 scorm_check_mode($this->scorm, $newattempt, $attempt, $this->student->id, $mode);
81 $this->assertEquals('off', $newattempt);
83 $scoes = scorm_get_scoes($this->scorm->id);
84 $sco = array_pop($scoes);
85 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
86 $newattempt = 'on';
87 scorm_check_mode($this->scorm, $newattempt, $attempt, $this->student->id, $mode);
88 $this->assertEquals('on', $newattempt);
90 // Now do the same with a SCORM 2004 package.
91 $record = new stdClass();
92 $record->course = $this->course->id;
93 $record->packagefilepath = $CFG->dirroot.'/mod/scorm/tests/packages/RuntimeBasicCalls_SCORM20043rdEdition.zip';
94 $scorm13 = $this->getDataGenerator()->create_module('scorm', $record);
95 $newattempt = 'on';
96 $attempt = 1;
97 $mode = 'normal';
98 scorm_check_mode($scorm13, $newattempt, $attempt, $this->student->id, $mode);
99 $this->assertEquals('off', $newattempt);
101 $scoes = scorm_get_scoes($scorm13->id);
102 $sco = array_pop($scoes);
103 scorm_insert_track($this->student->id, $scorm13->id, $sco->id, 1, 'cmi.completion_status', 'completed');
105 $newattempt = 'on';
106 $attempt = 1;
107 $mode = 'normal';
108 scorm_check_mode($scorm13, $newattempt, $attempt, $this->student->id, $mode);
109 $this->assertEquals('on', $newattempt);
113 * Test scorm_view
114 * @return void
116 public function test_scorm_view() {
117 global $CFG;
119 // Trigger and capture the event.
120 $sink = $this->redirectEvents();
122 scorm_view($this->scorm, $this->course, $this->cm, $this->context);
124 $events = $sink->get_events();
125 $this->assertCount(1, $events);
126 $event = array_shift($events);
128 // Checking that the event contains the expected values.
129 $this->assertInstanceOf('\mod_scorm\event\course_module_viewed', $event);
130 $this->assertEquals($this->context, $event->get_context());
131 $url = new \moodle_url('/mod/scorm/view.php', array('id' => $this->cm->id));
132 $this->assertEquals($url, $event->get_url());
133 $this->assertEventContextNotUsed($event);
134 $this->assertNotEmpty($event->get_name());
138 * Test scorm_get_availability_status and scorm_require_available
139 * @return void
141 public function test_scorm_check_and_require_available() {
142 global $DB;
144 // Set to the student user.
145 self::setUser($this->student);
147 // Usual case.
148 list($status, $warnings) = scorm_get_availability_status($this->scorm, false);
149 $this->assertEquals(true, $status);
150 $this->assertCount(0, $warnings);
152 // SCORM not open.
153 $this->scorm->timeopen = time() + DAYSECS;
154 list($status, $warnings) = scorm_get_availability_status($this->scorm, false);
155 $this->assertEquals(false, $status);
156 $this->assertCount(1, $warnings);
158 // SCORM closed.
159 $this->scorm->timeopen = 0;
160 $this->scorm->timeclose = time() - DAYSECS;
161 list($status, $warnings) = scorm_get_availability_status($this->scorm, false);
162 $this->assertEquals(false, $status);
163 $this->assertCount(1, $warnings);
165 // SCORM not open and closed.
166 $this->scorm->timeopen = time() + DAYSECS;
167 list($status, $warnings) = scorm_get_availability_status($this->scorm, false);
168 $this->assertEquals(false, $status);
169 $this->assertCount(2, $warnings);
171 // Now additional checkings with different parameters values.
172 list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context);
173 $this->assertEquals(false, $status);
174 $this->assertCount(2, $warnings);
176 // SCORM not open.
177 $this->scorm->timeopen = time() + DAYSECS;
178 $this->scorm->timeclose = 0;
179 list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context);
180 $this->assertEquals(false, $status);
181 $this->assertCount(1, $warnings);
183 // SCORM closed.
184 $this->scorm->timeopen = 0;
185 $this->scorm->timeclose = time() - DAYSECS;
186 list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context);
187 $this->assertEquals(false, $status);
188 $this->assertCount(1, $warnings);
190 // SCORM not open and closed.
191 $this->scorm->timeopen = time() + DAYSECS;
192 list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context);
193 $this->assertEquals(false, $status);
194 $this->assertCount(2, $warnings);
196 // As teacher now.
197 self::setUser($this->teacher);
199 // SCORM not open and closed.
200 $this->scorm->timeopen = time() + DAYSECS;
201 list($status, $warnings) = scorm_get_availability_status($this->scorm, false);
202 $this->assertEquals(false, $status);
203 $this->assertCount(2, $warnings);
205 // Now, we use the special capability.
206 // SCORM not open and closed.
207 $this->scorm->timeopen = time() + DAYSECS;
208 list($status, $warnings) = scorm_get_availability_status($this->scorm, true, $this->context);
209 $this->assertEquals(true, $status);
210 $this->assertCount(0, $warnings);
212 // Check exceptions does not broke anything.
213 scorm_require_available($this->scorm, true, $this->context);
214 // Now, expect exceptions.
215 $this->expectException('moodle_exception');
216 $this->expectExceptionMessage(get_string("notopenyet", "scorm", userdate($this->scorm->timeopen)));
218 // Now as student other condition.
219 self::setUser($this->student);
220 $this->scorm->timeopen = 0;
221 $this->scorm->timeclose = time() - DAYSECS;
223 $this->expectException('moodle_exception');
224 $this->expectExceptionMessage(get_string("expired", "scorm", userdate($this->scorm->timeclose)));
225 scorm_require_available($this->scorm, false);
229 * Test scorm_get_last_completed_attempt
231 * @return void
233 public function test_scorm_get_last_completed_attempt() {
234 $this->assertEquals(1, scorm_get_last_completed_attempt($this->scorm->id, $this->student->id));
237 public function test_scorm_core_calendar_provide_event_action_open() {
238 $this->resetAfterTest();
240 $this->setAdminUser();
242 // Create a course.
243 $course = $this->getDataGenerator()->create_course();
245 // Create a scorm activity.
246 $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id,
247 'timeopen' => time() - DAYSECS, 'timeclose' => time() + DAYSECS));
249 // Create a calendar event.
250 $event = $this->create_action_event($course->id, $scorm->id, SCORM_EVENT_TYPE_OPEN);
252 // Only students see scorm events.
253 $this->setUser($this->student);
255 // Create an action factory.
256 $factory = new \core_calendar\action_factory();
258 // Decorate action event.
259 $actionevent = mod_scorm_core_calendar_provide_event_action($event, $factory);
261 // Confirm the event was decorated.
262 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
263 $this->assertEquals(get_string('enter', 'scorm'), $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());
269 public function test_scorm_core_calendar_provide_event_action_closed() {
270 $this->resetAfterTest();
272 $this->setAdminUser();
274 // Create a course.
275 $course = $this->getDataGenerator()->create_course();
277 // Create a scorm activity.
278 $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id,
279 'timeclose' => time() - DAYSECS));
281 // Create a calendar event.
282 $event = $this->create_action_event($course->id, $scorm->id, SCORM_EVENT_TYPE_OPEN);
284 // Create an action factory.
285 $factory = new \core_calendar\action_factory();
287 // Decorate action event.
288 $actionevent = mod_scorm_core_calendar_provide_event_action($event, $factory);
290 // No event on the dashboard if module is closed.
291 $this->assertNull($actionevent);
294 public function test_scorm_core_calendar_provide_event_action_open_in_future() {
295 $this->resetAfterTest();
297 $this->setAdminUser();
299 // Create a course.
300 $course = $this->getDataGenerator()->create_course();
302 // Create a scorm activity.
303 $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id,
304 'timeopen' => time() + DAYSECS));
306 // Create a calendar event.
307 $event = $this->create_action_event($course->id, $scorm->id, SCORM_EVENT_TYPE_OPEN);
309 // Only students see scorm events.
310 $this->setUser($this->student);
312 // Create an action factory.
313 $factory = new \core_calendar\action_factory();
315 // Decorate action event.
316 $actionevent = mod_scorm_core_calendar_provide_event_action($event, $factory);
318 // Confirm the event was decorated.
319 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
320 $this->assertEquals(get_string('enter', 'scorm'), $actionevent->get_name());
321 $this->assertInstanceOf('moodle_url', $actionevent->get_url());
322 $this->assertEquals(1, $actionevent->get_item_count());
323 $this->assertFalse($actionevent->is_actionable());
326 public function test_scorm_core_calendar_provide_event_action_no_time_specified() {
327 $this->resetAfterTest();
329 $this->setAdminUser();
331 // Create a course.
332 $course = $this->getDataGenerator()->create_course();
334 // Create a scorm activity.
335 $scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $course->id));
337 // Create a calendar event.
338 $event = $this->create_action_event($course->id, $scorm->id, SCORM_EVENT_TYPE_OPEN);
340 // Only students see scorm events.
341 $this->setUser($this->student);
343 // Create an action factory.
344 $factory = new \core_calendar\action_factory();
346 // Decorate action event.
347 $actionevent = mod_scorm_core_calendar_provide_event_action($event, $factory);
349 // Confirm the event was decorated.
350 $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
351 $this->assertEquals(get_string('enter', 'scorm'), $actionevent->get_name());
352 $this->assertInstanceOf('moodle_url', $actionevent->get_url());
353 $this->assertEquals(1, $actionevent->get_item_count());
354 $this->assertTrue($actionevent->is_actionable());
358 * Creates an action event.
360 * @param int $courseid
361 * @param int $instanceid The data id.
362 * @param string $eventtype The event type. eg. DATA_EVENT_TYPE_OPEN.
363 * @param int|null $timestart The start timestamp for the event
364 * @return bool|calendar_event
366 private function create_action_event($courseid, $instanceid, $eventtype, $timestart = null) {
367 $event = new stdClass();
368 $event->name = 'Calendar event';
369 $event->modulename = 'scorm';
370 $event->courseid = $courseid;
371 $event->instance = $instanceid;
372 $event->type = CALENDAR_EVENT_TYPE_ACTION;
373 $event->eventtype = $eventtype;
374 $event->eventtype = $eventtype;
376 if ($timestart) {
377 $event->timestart = $timestart;
378 } else {
379 $event->timestart = time();
382 return calendar_event::create($event);
386 * Test the callback responsible for returning the completion rule descriptions.
387 * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
388 * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
390 public function test_mod_scorm_completion_get_active_rule_descriptions() {
391 $this->resetAfterTest();
392 $this->setAdminUser();
394 // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
395 $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
396 $scorm1 = $this->getDataGenerator()->create_module('scorm', [
397 'course' => $course->id,
398 'completion' => 2,
399 'completionstatusrequired' => 6,
400 'completionscorerequired' => 5,
401 'completionstatusallscos' => 1
403 $scorm2 = $this->getDataGenerator()->create_module('scorm', [
404 'course' => $course->id,
405 'completion' => 2,
406 'completionstatusrequired' => null,
407 'completionscorerequired' => null,
408 'completionstatusallscos' => null
410 $cm1 = cm_info::create(get_coursemodule_from_instance('scorm', $scorm1->id));
411 $cm2 = cm_info::create(get_coursemodule_from_instance('scorm', $scorm2->id));
413 // Data for the stdClass input type.
414 // This type of input would occur when checking the default completion rules for an activity type, where we don't have
415 // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
416 $moddefaults = new stdClass();
417 $moddefaults->customdata = ['customcompletionrules' => [
418 'completionstatusrequired' => 6,
419 'completionscorerequired' => 5,
420 'completionstatusallscos' => 1
422 $moddefaults->completion = 2;
424 // Determine the selected statuses using a bitwise operation.
425 $cvalues = array();
426 foreach (scorm_status_options(true) as $key => $value) {
427 if (($scorm1->completionstatusrequired & $key) == $key) {
428 $cvalues[] = $value;
431 $statusstring = implode(', ', $cvalues);
433 $activeruledescriptions = [
434 get_string('completionstatusrequireddesc', 'scorm', $statusstring),
435 get_string('completionscorerequireddesc', 'scorm', $scorm1->completionscorerequired),
436 get_string('completionstatusallscos', 'scorm'),
438 $this->assertEquals(mod_scorm_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
439 $this->assertEquals(mod_scorm_get_completion_active_rule_descriptions($cm2), []);
440 $this->assertEquals(mod_scorm_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
441 $this->assertEquals(mod_scorm_get_completion_active_rule_descriptions(new stdClass()), []);
445 * An unkown event type should not change the scorm instance.
447 public function test_mod_scorm_core_calendar_event_timestart_updated_unknown_event() {
448 global $CFG, $DB;
449 require_once($CFG->dirroot . "/calendar/lib.php");
451 $this->resetAfterTest(true);
452 $this->setAdminUser();
453 $generator = $this->getDataGenerator();
454 $course = $generator->create_course();
455 $scormgenerator = $generator->get_plugin_generator('mod_scorm');
456 $timeopen = time();
457 $timeclose = $timeopen + DAYSECS;
458 $scorm = $scormgenerator->create_instance(['course' => $course->id]);
459 $scorm->timeopen = $timeopen;
460 $scorm->timeclose = $timeclose;
461 $DB->update_record('scorm', $scorm);
463 // Create a valid event.
464 $event = new \calendar_event([
465 'name' => 'Test event',
466 'description' => '',
467 'format' => 1,
468 'courseid' => $course->id,
469 'groupid' => 0,
470 'userid' => 2,
471 'modulename' => 'scorm',
472 'instance' => $scorm->id,
473 'eventtype' => SCORM_EVENT_TYPE_OPEN . "SOMETHING ELSE",
474 'timestart' => 1,
475 'timeduration' => 86400,
476 'visible' => 1
479 mod_scorm_core_calendar_event_timestart_updated($event, $scorm);
481 $scorm = $DB->get_record('scorm', ['id' => $scorm->id]);
482 $this->assertEquals($timeopen, $scorm->timeopen);
483 $this->assertEquals($timeclose, $scorm->timeclose);
487 * A SCORM_EVENT_TYPE_OPEN event should update the timeopen property of
488 * the scorm activity.
490 public function test_mod_scorm_core_calendar_event_timestart_updated_open_event() {
491 global $CFG, $DB;
492 require_once($CFG->dirroot . "/calendar/lib.php");
494 $this->resetAfterTest(true);
495 $this->setAdminUser();
496 $generator = $this->getDataGenerator();
497 $course = $generator->create_course();
498 $scormgenerator = $generator->get_plugin_generator('mod_scorm');
499 $timeopen = time();
500 $timeclose = $timeopen + DAYSECS;
501 $timemodified = 1;
502 $newtimeopen = $timeopen - DAYSECS;
503 $scorm = $scormgenerator->create_instance(['course' => $course->id]);
504 $scorm->timeopen = $timeopen;
505 $scorm->timeclose = $timeclose;
506 $scorm->timemodified = $timemodified;
507 $DB->update_record('scorm', $scorm);
509 // Create a valid event.
510 $event = new \calendar_event([
511 'name' => 'Test event',
512 'description' => '',
513 'format' => 1,
514 'courseid' => $course->id,
515 'groupid' => 0,
516 'userid' => 2,
517 'modulename' => 'scorm',
518 'instance' => $scorm->id,
519 'eventtype' => SCORM_EVENT_TYPE_OPEN,
520 'timestart' => $newtimeopen,
521 'timeduration' => 86400,
522 'visible' => 1
525 // Trigger and capture the event when adding a contact.
526 $sink = $this->redirectEvents();
528 mod_scorm_core_calendar_event_timestart_updated($event, $scorm);
530 $triggeredevents = $sink->get_events();
531 $moduleupdatedevents = array_filter($triggeredevents, function($e) {
532 return is_a($e, 'core\event\course_module_updated');
535 $scorm = $DB->get_record('scorm', ['id' => $scorm->id]);
536 // Ensure the timeopen property matches the event timestart.
537 $this->assertEquals($newtimeopen, $scorm->timeopen);
538 // Ensure the timeclose isn't changed.
539 $this->assertEquals($timeclose, $scorm->timeclose);
540 // Ensure the timemodified property has been changed.
541 $this->assertNotEquals($timemodified, $scorm->timemodified);
542 // Confirm that a module updated event is fired when the module
543 // is changed.
544 $this->assertNotEmpty($moduleupdatedevents);
548 * A SCORM_EVENT_TYPE_CLOSE event should update the timeclose property of
549 * the scorm activity.
551 public function test_mod_scorm_core_calendar_event_timestart_updated_close_event() {
552 global $CFG, $DB;
553 require_once($CFG->dirroot . "/calendar/lib.php");
555 $this->resetAfterTest(true);
556 $this->setAdminUser();
557 $generator = $this->getDataGenerator();
558 $course = $generator->create_course();
559 $scormgenerator = $generator->get_plugin_generator('mod_scorm');
560 $timeopen = time();
561 $timeclose = $timeopen + DAYSECS;
562 $timemodified = 1;
563 $newtimeclose = $timeclose + DAYSECS;
564 $scorm = $scormgenerator->create_instance(['course' => $course->id]);
565 $scorm->timeopen = $timeopen;
566 $scorm->timeclose = $timeclose;
567 $scorm->timemodified = $timemodified;
568 $DB->update_record('scorm', $scorm);
570 // Create a valid event.
571 $event = new \calendar_event([
572 'name' => 'Test event',
573 'description' => '',
574 'format' => 1,
575 'courseid' => $course->id,
576 'groupid' => 0,
577 'userid' => 2,
578 'modulename' => 'scorm',
579 'instance' => $scorm->id,
580 'eventtype' => SCORM_EVENT_TYPE_CLOSE,
581 'timestart' => $newtimeclose,
582 'timeduration' => 86400,
583 'visible' => 1
586 // Trigger and capture the event when adding a contact.
587 $sink = $this->redirectEvents();
589 mod_scorm_core_calendar_event_timestart_updated($event, $scorm);
591 $triggeredevents = $sink->get_events();
592 $moduleupdatedevents = array_filter($triggeredevents, function($e) {
593 return is_a($e, 'core\event\course_module_updated');
596 $scorm = $DB->get_record('scorm', ['id' => $scorm->id]);
597 // Ensure the timeclose property matches the event timestart.
598 $this->assertEquals($newtimeclose, $scorm->timeclose);
599 // Ensure the timeopen isn't changed.
600 $this->assertEquals($timeopen, $scorm->timeopen);
601 // Ensure the timemodified property has been changed.
602 $this->assertNotEquals($timemodified, $scorm->timemodified);
603 // Confirm that a module updated event is fired when the module
604 // is changed.
605 $this->assertNotEmpty($moduleupdatedevents);
609 * An unkown event type should not have any limits
611 public function test_mod_scorm_core_calendar_get_valid_event_timestart_range_unknown_event() {
612 global $CFG, $DB;
613 require_once($CFG->dirroot . "/calendar/lib.php");
615 $this->resetAfterTest(true);
616 $this->setAdminUser();
617 $generator = $this->getDataGenerator();
618 $course = $generator->create_course();
619 $timeopen = time();
620 $timeclose = $timeopen + DAYSECS;
621 $scorm = new \stdClass();
622 $scorm->timeopen = $timeopen;
623 $scorm->timeclose = $timeclose;
625 // Create a valid event.
626 $event = new \calendar_event([
627 'name' => 'Test event',
628 'description' => '',
629 'format' => 1,
630 'courseid' => $course->id,
631 'groupid' => 0,
632 'userid' => 2,
633 'modulename' => 'scorm',
634 'instance' => 1,
635 'eventtype' => SCORM_EVENT_TYPE_OPEN . "SOMETHING ELSE",
636 'timestart' => 1,
637 'timeduration' => 86400,
638 'visible' => 1
641 list ($min, $max) = mod_scorm_core_calendar_get_valid_event_timestart_range($event, $scorm);
642 $this->assertNull($min);
643 $this->assertNull($max);
647 * The open event should be limited by the scorm's timeclose property, if it's set.
649 public function test_mod_scorm_core_calendar_get_valid_event_timestart_range_open_event() {
650 global $CFG, $DB;
651 require_once($CFG->dirroot . "/calendar/lib.php");
653 $this->resetAfterTest(true);
654 $this->setAdminUser();
655 $generator = $this->getDataGenerator();
656 $course = $generator->create_course();
657 $timeopen = time();
658 $timeclose = $timeopen + DAYSECS;
659 $scorm = new \stdClass();
660 $scorm->timeopen = $timeopen;
661 $scorm->timeclose = $timeclose;
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' => 'scorm',
672 'instance' => 1,
673 'eventtype' => SCORM_EVENT_TYPE_OPEN,
674 'timestart' => 1,
675 'timeduration' => 86400,
676 'visible' => 1
679 // The max limit should be bounded by the timeclose value.
680 list ($min, $max) = mod_scorm_core_calendar_get_valid_event_timestart_range($event, $scorm);
682 $this->assertNull($min);
683 $this->assertEquals($timeclose, $max[0]);
685 // No timeclose value should result in no upper limit.
686 $scorm->timeclose = 0;
687 list ($min, $max) = mod_scorm_core_calendar_get_valid_event_timestart_range($event, $scorm);
689 $this->assertNull($min);
690 $this->assertNull($max);
694 * The close event should be limited by the scorm's timeopen property, if it's set.
696 public function test_mod_scorm_core_calendar_get_valid_event_timestart_range_close_event() {
697 global $CFG, $DB;
698 require_once($CFG->dirroot . "/calendar/lib.php");
700 $this->resetAfterTest(true);
701 $this->setAdminUser();
702 $generator = $this->getDataGenerator();
703 $course = $generator->create_course();
704 $timeopen = time();
705 $timeclose = $timeopen + DAYSECS;
706 $scorm = new \stdClass();
707 $scorm->timeopen = $timeopen;
708 $scorm->timeclose = $timeclose;
710 // Create a valid event.
711 $event = new \calendar_event([
712 'name' => 'Test event',
713 'description' => '',
714 'format' => 1,
715 'courseid' => $course->id,
716 'groupid' => 0,
717 'userid' => 2,
718 'modulename' => 'scorm',
719 'instance' => 1,
720 'eventtype' => SCORM_EVENT_TYPE_CLOSE,
721 'timestart' => 1,
722 'timeduration' => 86400,
723 'visible' => 1
726 // The max limit should be bounded by the timeclose value.
727 list ($min, $max) = mod_scorm_core_calendar_get_valid_event_timestart_range($event, $scorm);
729 $this->assertEquals($timeopen, $min[0]);
730 $this->assertNull($max);
732 // No timeclose value should result in no upper limit.
733 $scorm->timeopen = 0;
734 list ($min, $max) = mod_scorm_core_calendar_get_valid_event_timestart_range($event, $scorm);
736 $this->assertNull($min);
737 $this->assertNull($max);
741 * A user who does not have capabilities to add events to the calendar should be able to create a SCORM.
743 public function test_creation_with_no_calendar_capabilities() {
744 $this->resetAfterTest();
745 $course = self::getDataGenerator()->create_course();
746 $context = context_course::instance($course->id);
747 $user = self::getDataGenerator()->create_and_enrol($course, 'editingteacher');
748 $roleid = self::getDataGenerator()->create_role();
749 self::getDataGenerator()->role_assign($roleid, $user->id, $context->id);
750 assign_capability('moodle/calendar:manageentries', CAP_PROHIBIT, $roleid, $context, true);
751 $generator = self::getDataGenerator()->get_plugin_generator('mod_scorm');
752 // Create an instance as a user without the calendar capabilities.
753 $this->setUser($user);
754 $time = time();
755 $params = array(
756 'course' => $course->id,
757 'timeopen' => $time + 200,
758 'timeclose' => $time + 2000,
760 $generator->create_instance($params);