2 // This file is part of Moodle - http://moodle.org/
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.
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/>.
18 * SCORM module library functions tests
22 * @copyright 2015 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') ||
die();
31 require_once($CFG->dirroot
. '/webservice/tests/helpers.php');
32 require_once($CFG->dirroot
. '/mod/scorm/lib.php');
35 * SCORM module library functions tests
39 * @copyright 2015 Juan Leyva <juan@moodle.com>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43 class mod_scorm_lib_testcase
extends externallib_advanced_testcase
{
46 * Set up for every test
48 public function setUp() {
50 $this->resetAfterTest();
51 $this->setAdminUser();
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
);
60 $this->student
= self
::getDataGenerator()->create_user();
61 $this->teacher
= self
::getDataGenerator()->create_user();
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
74 public function test_scorm_check_mode() {
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');
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);
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');
108 scorm_check_mode($scorm13, $newattempt, $attempt, $this->student
->id
, $mode);
109 $this->assertEquals('on', $newattempt);
116 public function test_scorm_view() {
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
141 public function test_scorm_check_and_require_available() {
144 // Set to the student user.
145 self
::setUser($this->student
);
148 list($status, $warnings) = scorm_get_availability_status($this->scorm
, false);
149 $this->assertEquals(true, $status);
150 $this->assertCount(0, $warnings);
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);
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);
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);
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);
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
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();
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();
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();
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();
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;
377 $event->timestart
= $timestart;
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
,
399 'completionstatusrequired' => 6,
400 'completionscorerequired' => 5,
401 'completionstatusallscos' => 1
403 $scorm2 = $this->getDataGenerator()->create_module('scorm', [
404 'course' => $course->id
,
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.
426 foreach (scorm_status_options(true) as $key => $value) {
427 if (($scorm1->completionstatusrequired
& $key) == $key) {
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() {
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');
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',
468 'courseid' => $course->id
,
471 'modulename' => 'scorm',
472 'instance' => $scorm->id
,
473 'eventtype' => SCORM_EVENT_TYPE_OPEN
. "SOMETHING ELSE",
475 'timeduration' => 86400,
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() {
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');
500 $timeclose = $timeopen + DAYSECS
;
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',
514 'courseid' => $course->id
,
517 'modulename' => 'scorm',
518 'instance' => $scorm->id
,
519 'eventtype' => SCORM_EVENT_TYPE_OPEN
,
520 'timestart' => $newtimeopen,
521 'timeduration' => 86400,
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
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() {
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');
561 $timeclose = $timeopen + DAYSECS
;
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',
575 'courseid' => $course->id
,
578 'modulename' => 'scorm',
579 'instance' => $scorm->id
,
580 'eventtype' => SCORM_EVENT_TYPE_CLOSE
,
581 'timestart' => $newtimeclose,
582 'timeduration' => 86400,
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
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() {
613 require_once($CFG->dirroot
. "/calendar/lib.php");
615 $this->resetAfterTest(true);
616 $this->setAdminUser();
617 $generator = $this->getDataGenerator();
618 $course = $generator->create_course();
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',
630 'courseid' => $course->id
,
633 'modulename' => 'scorm',
635 'eventtype' => SCORM_EVENT_TYPE_OPEN
. "SOMETHING ELSE",
637 'timeduration' => 86400,
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() {
651 require_once($CFG->dirroot
. "/calendar/lib.php");
653 $this->resetAfterTest(true);
654 $this->setAdminUser();
655 $generator = $this->getDataGenerator();
656 $course = $generator->create_course();
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',
668 'courseid' => $course->id
,
671 'modulename' => 'scorm',
673 'eventtype' => SCORM_EVENT_TYPE_OPEN
,
675 'timeduration' => 86400,
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() {
698 require_once($CFG->dirroot
. "/calendar/lib.php");
700 $this->resetAfterTest(true);
701 $this->setAdminUser();
702 $generator = $this->getDataGenerator();
703 $course = $generator->create_course();
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',
715 'courseid' => $course->id
,
718 'modulename' => 'scorm',
720 'eventtype' => SCORM_EVENT_TYPE_CLOSE
,
722 'timeduration' => 86400,
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);
756 'course' => $course->id
,
757 'timeopen' => $time +
200,
758 'timeclose' => $time +
2000,
760 $generator->create_instance($params);