MDL-60057 mod_lesson: add unit tests for callbacks
[moodle.git] / mod / lesson / tests / lib_test.php
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/>.
17 /**
18  * Unit tests for mod/lesson/lib.php.
19  *
20  * @package    mod_lesson
21  * @category   test
22  * @copyright  2017 Jun Pataleta
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/mod/lesson/lib.php');
31 /**
32  * Unit tests for mod/lesson/lib.php.
33  *
34  * @copyright  2017 Jun Pataleta
35  * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
36  */
37 class mod_lesson_lib_testcase extends advanced_testcase {
38     /**
39      * Test for lesson_get_group_override_priorities().
40      */
41     public function test_lesson_get_group_override_priorities() {
42         global $DB;
43         $this->resetAfterTest();
44         $this->setAdminUser();
46         $dg = $this->getDataGenerator();
47         $course = $dg->create_course();
48         $lessonmodule = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id));
50         $this->assertNull(lesson_get_group_override_priorities($lessonmodule->id));
52         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
53         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
55         $now = 100;
56         $override1 = (object)[
57             'lessonid' => $lessonmodule->id,
58             'groupid' => $group1->id,
59             'available' => $now,
60             'deadline' => $now + 20
61         ];
62         $DB->insert_record('lesson_overrides', $override1);
64         $override2 = (object)[
65             'lessonid' => $lessonmodule->id,
66             'groupid' => $group2->id,
67             'available' => $now - 10,
68             'deadline' => $now + 10
69         ];
70         $DB->insert_record('lesson_overrides', $override2);
72         $priorities = lesson_get_group_override_priorities($lessonmodule->id);
73         $this->assertNotEmpty($priorities);
75         $openpriorities = $priorities['open'];
76         // Override 2's time open has higher priority since it is sooner than override 1's.
77         $this->assertEquals(2, $openpriorities[$override1->available]);
78         $this->assertEquals(1, $openpriorities[$override2->available]);
80         $closepriorities = $priorities['close'];
81         // Override 1's time close has higher priority since it is later than override 2's.
82         $this->assertEquals(1, $closepriorities[$override1->deadline]);
83         $this->assertEquals(2, $closepriorities[$override2->deadline]);
84     }
86     /**
87      * Test check_updates_since callback.
88      */
89     public function test_check_updates_since() {
90         global $DB;
92         $this->resetAfterTest();
93         $this->setAdminUser();
94         $course = new stdClass();
95         $course->groupmode = SEPARATEGROUPS;
96         $course->groupmodeforce = true;
97         $course = $this->getDataGenerator()->create_course($course);
99         // Create user.
100         $studentg1 = self::getDataGenerator()->create_user();
101         $teacherg1 = self::getDataGenerator()->create_user();
102         $studentg2 = self::getDataGenerator()->create_user();
104         // User enrolment.
105         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
106         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
107         $this->getDataGenerator()->enrol_user($studentg1->id, $course->id, $studentrole->id, 'manual');
108         $this->getDataGenerator()->enrol_user($teacherg1->id, $course->id, $teacherrole->id, 'manual');
109         $this->getDataGenerator()->enrol_user($studentg2->id, $course->id, $studentrole->id, 'manual');
111         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
112         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
113         groups_add_member($group1, $studentg1);
114         groups_add_member($group2, $studentg2);
116         $this->setCurrentTimeStart();
117         $record = array(
118             'course' => $course->id,
119             'custom' => 0,
120             'feedback' => 1,
121         );
122         $lessonmodule = $this->getDataGenerator()->create_module('lesson', $record);
123         // Convert to a lesson object.
124         $lesson = new lesson($lessonmodule);
125         $cm = $lesson->cm;
126         $cm = cm_info::create($cm);
128         // Check that upon creation, the updates are only about the new configuration created.
129         $onehourago = time() - HOURSECS;
130         $updates = lesson_check_updates_since($cm, $onehourago);
131         foreach ($updates as $el => $val) {
132             if ($el == 'configuration') {
133                 $this->assertTrue($val->updated);
134                 $this->assertTimeCurrent($val->timeupdated);
135             } else {
136                 $this->assertFalse($val->updated);
137             }
138         }
140         // Set up a generator to create content.
141         $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
142         $tfrecord = $generator->create_question_truefalse($lesson);
144         // Check now for pages and answers.
145         $updates = lesson_check_updates_since($cm, $onehourago);
146         $this->assertTrue($updates->pages->updated);
147         $this->assertCount(1, $updates->pages->itemids);
149         $this->assertTrue($updates->answers->updated);
150         $this->assertCount(2, $updates->answers->itemids);
152         // Now, do something in the lesson with the two users.
153         $this->setUser($studentg1);
154         mod_lesson_external::launch_attempt($lesson->id);
155         $data = array(
156             array(
157                 'name' => 'answerid',
158                 'value' => $DB->get_field('lesson_answers', 'id', array('pageid' => $tfrecord->id, 'jumpto' => -1)),
159             ),
160             array(
161                 'name' => '_qf__lesson_display_answer_form_truefalse',
162                 'value' => 1,
163             )
164         );
165         mod_lesson_external::process_page($lesson->id, $tfrecord->id, $data);
166         mod_lesson_external::finish_attempt($lesson->id);
168         $this->setUser($studentg2);
169         mod_lesson_external::launch_attempt($lesson->id);
170         $data = array(
171             array(
172                 'name' => 'answerid',
173                 'value' => $DB->get_field('lesson_answers', 'id', array('pageid' => $tfrecord->id, 'jumpto' => -1)),
174             ),
175             array(
176                 'name' => '_qf__lesson_display_answer_form_truefalse',
177                 'value' => 1,
178             )
179         );
180         mod_lesson_external::process_page($lesson->id, $tfrecord->id, $data);
181         mod_lesson_external::finish_attempt($lesson->id);
183         $this->setUser($studentg1);
184         $updates = lesson_check_updates_since($cm, $onehourago);
186         // Check question attempts, timers and new grades.
187         $this->assertTrue($updates->questionattempts->updated);
188         $this->assertCount(1, $updates->questionattempts->itemids);
190         $this->assertTrue($updates->grades->updated);
191         $this->assertCount(1, $updates->grades->itemids);
193         $this->assertTrue($updates->timers->updated);
194         $this->assertCount(1, $updates->timers->itemids);
196         // Now, as teacher, check that I can see the two users (even in separate groups).
197         $this->setUser($teacherg1);
198         $updates = lesson_check_updates_since($cm, $onehourago);
199         $this->assertTrue($updates->userquestionattempts->updated);
200         $this->assertCount(2, $updates->userquestionattempts->itemids);
202         $this->assertTrue($updates->usergrades->updated);
203         $this->assertCount(2, $updates->usergrades->itemids);
205         $this->assertTrue($updates->usertimers->updated);
206         $this->assertCount(2, $updates->usertimers->itemids);
208         // Now, teacher can't access all groups.
209         groups_add_member($group1, $teacherg1);
210         assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, context_module::instance($cm->id));
211         accesslib_clear_all_caches_for_unit_testing();
212         $updates = lesson_check_updates_since($cm, $onehourago);
213         // I will see only the studentg1 updates.
214         $this->assertTrue($updates->userquestionattempts->updated);
215         $this->assertCount(1, $updates->userquestionattempts->itemids);
217         $this->assertTrue($updates->usergrades->updated);
218         $this->assertCount(1, $updates->usergrades->itemids);
220         $this->assertTrue($updates->usertimers->updated);
221         $this->assertCount(1, $updates->usertimers->itemids);
222     }
224     public function test_lesson_core_calendar_provide_event_action_open() {
225         $this->resetAfterTest();
226         $this->setAdminUser();
227         // Create a course.
228         $course = $this->getDataGenerator()->create_course();
229         // Create a lesson activity.
230         $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id,
231             'available' => time() - DAYSECS, 'deadline' => time() + DAYSECS));
232         // Create a calendar event.
233         $event = $this->create_action_event($course->id, $lesson->id, LESSON_EVENT_TYPE_OPEN);
234         // Create an action factory.
235         $factory = new \core_calendar\action_factory();
236         // Decorate action event.
237         $actionevent = mod_lesson_core_calendar_provide_event_action($event, $factory);
238         // Confirm the event was decorated.
239         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
240         $this->assertEquals(get_string('startlesson', 'lesson'), $actionevent->get_name());
241         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
242         $this->assertEquals(1, $actionevent->get_item_count());
243         $this->assertTrue($actionevent->is_actionable());
244     }
246     public function test_lesson_core_calendar_provide_event_action_closed() {
247         $this->resetAfterTest();
248         $this->setAdminUser();
250         // Create a course.
251         $course = $this->getDataGenerator()->create_course();
253         // Create a lesson activity.
254         $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id,
255             'deadline' => time() - DAYSECS));
257         // Create a calendar event.
258         $event = $this->create_action_event($course->id, $lesson->id, LESSON_EVENT_TYPE_OPEN);
260         // Create an action factory.
261         $factory = new \core_calendar\action_factory();
263         // Decorate action event.
264         $actionevent = mod_lesson_core_calendar_provide_event_action($event, $factory);
266         // Confirm the event was decorated.
267         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
268         $this->assertEquals(get_string('startlesson', 'lesson'), $actionevent->get_name());
269         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
270         $this->assertEquals(1, $actionevent->get_item_count());
271         $this->assertFalse($actionevent->is_actionable());
272     }
274     public function test_lesson_core_calendar_provide_event_action_open_in_future() {
275         $this->resetAfterTest();
276         $this->setAdminUser();
278         // Create a course.
279         $course = $this->getDataGenerator()->create_course();
281         // Create a lesson activity.
282         $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id,
283             'available' => time() + DAYSECS));
285         // Create a calendar event.
286         $event = $this->create_action_event($course->id, $lesson->id, LESSON_EVENT_TYPE_OPEN);
288         // Create an action factory.
289         $factory = new \core_calendar\action_factory();
291         // Decorate action event.
292         $actionevent = mod_lesson_core_calendar_provide_event_action($event, $factory);
294         // Confirm the event was decorated.
295         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
296         $this->assertEquals(get_string('startlesson', 'lesson'), $actionevent->get_name());
297         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
298         $this->assertEquals(1, $actionevent->get_item_count());
299         $this->assertFalse($actionevent->is_actionable());
300     }
302     public function test_lesson_core_calendar_provide_event_action_no_time_specified() {
303         $this->resetAfterTest();
304         $this->setAdminUser();
306         // Create a course.
307         $course = $this->getDataGenerator()->create_course();
309         // Create a lesson activity.
310         $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id));
312         // Create a calendar event.
313         $event = $this->create_action_event($course->id, $lesson->id, LESSON_EVENT_TYPE_OPEN);
315         // Create an action factory.
316         $factory = new \core_calendar\action_factory();
318         // Decorate action event.
319         $actionevent = mod_lesson_core_calendar_provide_event_action($event, $factory);
321         // Confirm the event was decorated.
322         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
323         $this->assertEquals(get_string('startlesson', 'lesson'), $actionevent->get_name());
324         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
325         $this->assertEquals(1, $actionevent->get_item_count());
326         $this->assertTrue($actionevent->is_actionable());
327     }
329     public function test_lesson_core_calendar_provide_event_action_after_attempt() {
330         global $DB;
332         $this->resetAfterTest();
333         $this->setAdminUser();
335         // Create a course.
336         $course = $this->getDataGenerator()->create_course();
338         // Create user.
339         $student = self::getDataGenerator()->create_user();
341         // Create a lesson activity.
342         $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $course->id));
344         // Create a calendar event.
345         $event = $this->create_action_event($course->id, $lesson->id, LESSON_EVENT_TYPE_OPEN);
347         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
348         $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
350         $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
351         $tfrecord = $generator->create_question_truefalse($lesson);
353         // Now, do something in the lesson.
354         $this->setUser($student);
355         mod_lesson_external::launch_attempt($lesson->id);
356         $data = array(
357             array(
358                 'name' => 'answerid',
359                 'value' => $DB->get_field('lesson_answers', 'id', array('pageid' => $tfrecord->id, 'jumpto' => -1)),
360             ),
361             array(
362                 'name' => '_qf__lesson_display_answer_form_truefalse',
363                 'value' => 1,
364             )
365         );
366         mod_lesson_external::process_page($lesson->id, $tfrecord->id, $data);
367         mod_lesson_external::finish_attempt($lesson->id);
369         // Create an action factory.
370         $factory = new \core_calendar\action_factory();
372         // Decorate action event.
373         $action = mod_lesson_core_calendar_provide_event_action($event, $factory);
375         // Confirm there was no action for the user.
376         $this->assertNull($action);
377     }
379     /**
380      * Creates an action event.
381      *
382      * @param int $courseid
383      * @param int $instanceid The lesson id.
384      * @param string $eventtype The event type. eg. LESSON_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  = 'lesson';
391         $event->courseid = $courseid;
392         $event->instance = $instanceid;
393         $event->type = CALENDAR_EVENT_TYPE_ACTION;
394         $event->eventtype = $eventtype;
395         $event->timestart = time();
396         return calendar_event::create($event);
397     }
399     /**
400      * Test the callback responsible for returning the completion rule descriptions.
401      * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
402      * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
403      */
404     public function test_mod_lesson_completion_get_active_rule_descriptions() {
405         $this->resetAfterTest();
406         $this->setAdminUser();
408         // Two activities, both with automatic completion. One has the 'completionsubmit' rule, one doesn't.
409         $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
410         $lesson1 = $this->getDataGenerator()->create_module('lesson', [
411             'course' => $course->id,
412             'completion' => 2,
413             'completionendreached' => 1,
414             'completiontimespent' => 3600
415         ]);
416         $lesson2 = $this->getDataGenerator()->create_module('lesson', [
417             'course' => $course->id,
418             'completion' => 2,
419             'completionendreached' => 0,
420             'completiontimespent' => 0
421         ]);
422         $cm1 = cm_info::create(get_coursemodule_from_instance('lesson', $lesson1->id));
423         $cm2 = cm_info::create(get_coursemodule_from_instance('lesson', $lesson2->id));
425         // Data for the stdClass input type.
426         // This type of input would occur when checking the default completion rules for an activity type, where we don't have
427         // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
428         $moddefaults = new stdClass();
429         $moddefaults->customdata = ['customcompletionrules' => [
430             'completionendreached' => 1,
431             'completiontimespent' => 3600
432         ]];
433         $moddefaults->completion = 2;
435         $activeruledescriptions = [
436             get_string('completionendreached_desc', 'lesson'),
437             get_string('completiontimespentdesc', 'lesson', format_time(3600)),
438         ];
439         $this->assertEquals(mod_lesson_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
440         $this->assertEquals(mod_lesson_get_completion_active_rule_descriptions($cm2), []);
441         $this->assertEquals(mod_lesson_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
442         $this->assertEquals(mod_lesson_get_completion_active_rule_descriptions(new stdClass()), []);
443     }
445     /**
446      * An unknown event type should not change the lesson instance.
447      */
448     public function test_mod_lesson_core_calendar_event_timestart_updated_unknown_event() {
449         global $CFG, $DB;
450         require_once($CFG->dirroot . "/calendar/lib.php");
452         $this->resetAfterTest(true);
453         $this->setAdminUser();
454         $generator = $this->getDataGenerator();
455         $course = $generator->create_course();
456         $lessongenerator = $generator->get_plugin_generator('mod_lesson');
457         $timeopen = time();
458         $timeclose = $timeopen + DAYSECS;
459         $lesson = $lessongenerator->create_instance(['course' => $course->id]);
460         $lesson->available = $timeopen;
461         $lesson->deadline = $timeclose;
462         $DB->update_record('lesson', $lesson);
464         // Create a valid event.
465         $event = new \calendar_event([
466             'name' => 'Test event',
467             'description' => '',
468             'format' => 1,
469             'courseid' => $course->id,
470             'groupid' => 0,
471             'userid' => 2,
472             'modulename' => 'lesson',
473             'instance' => $lesson->id,
474             'eventtype' => LESSON_EVENT_TYPE_OPEN . "SOMETHING ELSE",
475             'timestart' => 1,
476             'timeduration' => 86400,
477             'visible' => 1
478         ]);
480         mod_lesson_core_calendar_event_timestart_updated($event, $lesson);
481         $lesson = $DB->get_record('lesson', ['id' => $lesson->id]);
482         $this->assertEquals($timeopen, $lesson->available);
483         $this->assertEquals($timeclose, $lesson->deadline);
484     }
486     /**
487      * A LESSON_EVENT_TYPE_OPEN event should update the available property of the lesson activity.
488      */
489     public function test_mod_lesson_core_calendar_event_timestart_updated_open_event() {
490         global $CFG, $DB;
491         require_once($CFG->dirroot . "/calendar/lib.php");
493         $this->resetAfterTest(true);
494         $this->setAdminUser();
495         $generator = $this->getDataGenerator();
496         $course = $generator->create_course();
497         $lessongenerator = $generator->get_plugin_generator('mod_lesson');
498         $timeopen = time();
499         $timeclose = $timeopen + DAYSECS;
500         $timemodified = 1;
501         $newtimeopen = $timeopen - DAYSECS;
502         $lesson = $lessongenerator->create_instance(['course' => $course->id]);
503         $lesson->available = $timeopen;
504         $lesson->deadline = $timeclose;
505         $lesson->timemodified = $timemodified;
506         $DB->update_record('lesson', $lesson);
508         // Create a valid event.
509         $event = new \calendar_event([
510             'name' => 'Test event',
511             'description' => '',
512             'format' => 1,
513             'courseid' => $course->id,
514             'groupid' => 0,
515             'userid' => 2,
516             'modulename' => 'lesson',
517             'instance' => $lesson->id,
518             'eventtype' => LESSON_EVENT_TYPE_OPEN,
519             'timestart' => $newtimeopen,
520             'timeduration' => 86400,
521             'visible' => 1
522         ]);
524         // Trigger and capture the event when adding a contact.
525         $sink = $this->redirectEvents();
526         mod_lesson_core_calendar_event_timestart_updated($event, $lesson);
527         $triggeredevents = $sink->get_events();
528         $moduleupdatedevents = array_filter($triggeredevents, function($e) {
529             return is_a($e, 'core\event\course_module_updated');
530         });
531         $lesson = $DB->get_record('lesson', ['id' => $lesson->id]);
533         // Ensure the available property matches the event timestart.
534         $this->assertEquals($newtimeopen, $lesson->available);
536         // Ensure the deadline isn't changed.
537         $this->assertEquals($timeclose, $lesson->deadline);
539         // Ensure the timemodified property has been changed.
540         $this->assertNotEquals($timemodified, $lesson->timemodified);
542         // Confirm that a module updated event is fired when the module is changed.
543         $this->assertNotEmpty($moduleupdatedevents);
544     }
546     /**
547      * A LESSON_EVENT_TYPE_CLOSE event should update the deadline property of the lesson activity.
548      */
549     public function test_mod_lesson_core_calendar_event_timestart_updated_close_event() {
550         global $CFG, $DB;
551         require_once($CFG->dirroot . "/calendar/lib.php");
552         $this->resetAfterTest(true);
553         $this->setAdminUser();
554         $generator = $this->getDataGenerator();
555         $course = $generator->create_course();
556         $lessongenerator = $generator->get_plugin_generator('mod_lesson');
557         $timeopen = time();
558         $timeclose = $timeopen + DAYSECS;
559         $timemodified = 1;
560         $newtimeclose = $timeclose + DAYSECS;
561         $lesson = $lessongenerator->create_instance(['course' => $course->id]);
562         $lesson->available = $timeopen;
563         $lesson->deadline = $timeclose;
564         $lesson->timemodified = $timemodified;
565         $DB->update_record('lesson', $lesson);
566         // Create a valid event.
567         $event = new \calendar_event([
568             'name' => 'Test event',
569             'description' => '',
570             'format' => 1,
571             'courseid' => $course->id,
572             'groupid' => 0,
573             'userid' => 2,
574             'modulename' => 'lesson',
575             'instance' => $lesson->id,
576             'eventtype' => LESSON_EVENT_TYPE_CLOSE,
577             'timestart' => $newtimeclose,
578             'timeduration' => 86400,
579             'visible' => 1
580         ]);
581         // Trigger and capture the event when adding a contact.
582         $sink = $this->redirectEvents();
583         mod_lesson_core_calendar_event_timestart_updated($event, $lesson);
584         $triggeredevents = $sink->get_events();
585         $moduleupdatedevents = array_filter($triggeredevents, function($e) {
586             return is_a($e, 'core\event\course_module_updated');
587         });
588         $lesson = $DB->get_record('lesson', ['id' => $lesson->id]);
589         // Ensure the deadline property matches the event timestart.
590         $this->assertEquals($newtimeclose, $lesson->deadline);
591         // Ensure the available isn't changed.
592         $this->assertEquals($timeopen, $lesson->available);
593         // Ensure the timemodified property has been changed.
594         $this->assertNotEquals($timemodified, $lesson->timemodified);
595         // Confirm that a module updated event is fired when the module is changed.
596         $this->assertNotEmpty($moduleupdatedevents);
597     }
599     /**
600      * An unknown event type should not have any limits.
601      */
602     public function test_mod_lesson_core_calendar_get_valid_event_timestart_range_unknown_event() {
603         global $CFG;
604         require_once($CFG->dirroot . "/calendar/lib.php");
606         $this->resetAfterTest(true);
607         $this->setAdminUser();
608         $generator = $this->getDataGenerator();
609         $course = $generator->create_course();
610         $timeopen = time();
611         $timeclose = $timeopen + DAYSECS;
612         $lesson = new \stdClass();
613         $lesson->available = $timeopen;
614         $lesson->deadline = $timeclose;
616         // Create a valid event.
617         $event = new \calendar_event([
618             'name' => 'Test event',
619             'description' => '',
620             'format' => 1,
621             'courseid' => $course->id,
622             'groupid' => 0,
623             'userid' => 2,
624             'modulename' => 'lesson',
625             'instance' => 1,
626             'eventtype' => LESSON_EVENT_TYPE_OPEN . "SOMETHING ELSE",
627             'timestart' => 1,
628             'timeduration' => 86400,
629             'visible' => 1
630         ]);
632         list ($min, $max) = mod_lesson_core_calendar_get_valid_event_timestart_range($event, $lesson);
633         $this->assertNull($min);
634         $this->assertNull($max);
635     }
637     /**
638      * The open event should be limited by the lesson's deadline property, if it's set.
639      */
640     public function test_mod_lesson_core_calendar_get_valid_event_timestart_range_open_event() {
641         global $CFG;
642         require_once($CFG->dirroot . "/calendar/lib.php");
644         $this->resetAfterTest(true);
645         $this->setAdminUser();
646         $generator = $this->getDataGenerator();
647         $course = $generator->create_course();
648         $timeopen = time();
649         $timeclose = $timeopen + DAYSECS;
650         $lesson = new \stdClass();
651         $lesson->available = $timeopen;
652         $lesson->deadline = $timeclose;
654         // Create a valid event.
655         $event = new \calendar_event([
656             'name' => 'Test event',
657             'description' => '',
658             'format' => 1,
659             'courseid' => $course->id,
660             'groupid' => 0,
661             'userid' => 2,
662             'modulename' => 'lesson',
663             'instance' => 1,
664             'eventtype' => LESSON_EVENT_TYPE_OPEN,
665             'timestart' => 1,
666             'timeduration' => 86400,
667             'visible' => 1
668         ]);
670         // The max limit should be bounded by the timeclose value.
671         list ($min, $max) = mod_lesson_core_calendar_get_valid_event_timestart_range($event, $lesson);
672         $this->assertNull($min);
673         $this->assertEquals($timeclose, $max[0]);
675         // No timeclose value should result in no upper limit.
676         $lesson->deadline = 0;
677         list ($min, $max) = mod_lesson_core_calendar_get_valid_event_timestart_range($event, $lesson);
678         $this->assertNull($min);
679         $this->assertNull($max);
680     }
682     /**
683      * The close event should be limited by the lesson's available property, if it's set.
684      */
685     public function test_mod_lesson_core_calendar_get_valid_event_timestart_range_close_event() {
686         global $CFG;
687         require_once($CFG->dirroot . "/calendar/lib.php");
689         $this->resetAfterTest(true);
690         $this->setAdminUser();
691         $generator = $this->getDataGenerator();
692         $course = $generator->create_course();
693         $timeopen = time();
694         $timeclose = $timeopen + DAYSECS;
695         $lesson = new \stdClass();
696         $lesson->available = $timeopen;
697         $lesson->deadline = $timeclose;
699         // Create a valid event.
700         $event = new \calendar_event([
701             'name' => 'Test event',
702             'description' => '',
703             'format' => 1,
704             'courseid' => $course->id,
705             'groupid' => 0,
706             'userid' => 2,
707             'modulename' => 'lesson',
708             'instance' => 1,
709             'eventtype' => LESSON_EVENT_TYPE_CLOSE,
710             'timestart' => 1,
711             'timeduration' => 86400,
712             'visible' => 1
713         ]);
715         // The max limit should be bounded by the timeclose value.
716         list ($min, $max) = mod_lesson_core_calendar_get_valid_event_timestart_range($event, $lesson);
717         $this->assertEquals($timeopen, $min[0]);
718         $this->assertNull($max);
720         // No deadline value should result in no upper limit.
721         $lesson->available = 0;
722         list ($min, $max) = mod_lesson_core_calendar_get_valid_event_timestart_range($event, $lesson);
723         $this->assertNull($min);
724         $this->assertNull($max);
725     }