MDL-57455 mod_data: Added PHPUnit tests
[moodle.git] / mod / data / 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 lib.php
19  *
20  * @package    mod_data
21  * @category   phpunit
22  * @copyright  2013 Adrian Greeve
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->dirroot . '/mod/data/lib.php');
31 /**
32  * Unit tests for lib.php
33  *
34  * @package    mod_data
35  * @copyright  2013 Adrian Greeve
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class mod_data_lib_testcase extends advanced_testcase {
40     /**
41      * @var moodle_database
42      */
43     protected $DB = null;
45     /**
46      * Tear Down to reset DB.
47      */
48     public function tearDown() {
49         global $DB;
51         if (isset($this->DB)) {
52             $DB = $this->DB;
53             $this->DB = null;
54         }
55     }
57     /**
58      * Confirms that completionentries is working
59      * Sets it to 1, confirms that
60      * it is not complete. Inserts a record and
61      * confirms that it is complete.
62      */
63     public function test_data_completion() {
64         global $DB, $CFG;
65         $this->resetAfterTest();
66         $this->setAdminUser();
67         $CFG->enablecompletion = 1;
68         $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
69         $record = new stdClass();
70         $record->course = $course->id;
71         $record->name = "Mod data completion test";
72         $record->intro = "Some intro of some sort";
73         $record->completionentries = "1";
74         /* completion=2 means Show activity commplete when condition is met and completionentries means 1 record is
75          * required for the activity to be considered complete
76          */
77         $module = $this->getDataGenerator()->create_module('data', $record, array('completion' => 2, 'completionentries' => 1));
79         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
80         $completion = new completion_info($course);
81         $completiondata = $completion->get_data($cm, true, 0);
82         /* Confirm it is not complete as there are no entries */
83         $this->assertNotEquals(1, $completiondata->completionstate);
85         $field = data_get_field_new('text', $module);
86         $fielddetail = new stdClass();
87         $fielddetail->d = $module->id;
88         $fielddetail->mode = 'add';
89         $fielddetail->type = 'text';
90         $fielddetail->sesskey = sesskey();
91         $fielddetail->name = 'Name';
92         $fielddetail->description = 'Some name';
94         $field->define_field($fielddetail);
95         $field->insert_field();
96         $recordid = data_add_record($module);
98         $datacontent = array();
99         $datacontent['fieldid'] = $field->field->id;
100         $datacontent['recordid'] = $recordid;
101         $datacontent['content'] = 'Asterix';
102         $contentid = $DB->insert_record('data_content', $datacontent);
104         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
105         $completion = new completion_info($course);
106         $completiondata = $completion->get_data($cm);
107         /* Confirm it is complete because it has 1 entry */
108         $this->assertEquals(1, $completiondata->completionstate);
109     }
111     public function test_data_delete_record() {
112         global $DB;
114         $this->resetAfterTest();
116         // Create a record for deleting.
117         $this->setAdminUser();
118         $course = $this->getDataGenerator()->create_course();
119         $record = new stdClass();
120         $record->course = $course->id;
121         $record->name = "Mod data delete test";
122         $record->intro = "Some intro of some sort";
124         $module = $this->getDataGenerator()->create_module('data', $record);
126         $field = data_get_field_new('text', $module);
128         $fielddetail = new stdClass();
129         $fielddetail->d = $module->id;
130         $fielddetail->mode = 'add';
131         $fielddetail->type = 'text';
132         $fielddetail->sesskey = sesskey();
133         $fielddetail->name = 'Name';
134         $fielddetail->description = 'Some name';
136         $field->define_field($fielddetail);
137         $field->insert_field();
138         $recordid = data_add_record($module);
140         $datacontent = array();
141         $datacontent['fieldid'] = $field->field->id;
142         $datacontent['recordid'] = $recordid;
143         $datacontent['content'] = 'Asterix';
145         $contentid = $DB->insert_record('data_content', $datacontent);
146         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
148         // Check to make sure that we have a database record.
149         $data = $DB->get_records('data', array('id' => $module->id));
150         $this->assertEquals(1, count($data));
152         $datacontent = $DB->get_records('data_content', array('id' => $contentid));
153         $this->assertEquals(1, count($datacontent));
155         $datafields = $DB->get_records('data_fields', array('id' => $field->field->id));
156         $this->assertEquals(1, count($datafields));
158         $datarecords = $DB->get_records('data_records', array('id' => $recordid));
159         $this->assertEquals(1, count($datarecords));
161         // Test to see if a failed delete returns false.
162         $result = data_delete_record(8798, $module, $course->id, $cm->id);
163         $this->assertFalse($result);
165         // Delete the record.
166         $result = data_delete_record($recordid, $module, $course->id, $cm->id);
168         // Check that all of the record is gone.
169         $datacontent = $DB->get_records('data_content', array('id' => $contentid));
170         $this->assertEquals(0, count($datacontent));
172         $datarecords = $DB->get_records('data_records', array('id' => $recordid));
173         $this->assertEquals(0, count($datarecords));
175         // Make sure the function returns true on a successful deletion.
176         $this->assertTrue($result);
177     }
179     /**
180      * Test comment_created event.
181      */
182     public function test_data_comment_created_event() {
183         global $CFG, $DB;
184         require_once($CFG->dirroot . '/comment/lib.php');
186         $this->resetAfterTest();
188         // Create a record for deleting.
189         $this->setAdminUser();
190         $course = $this->getDataGenerator()->create_course();
191         $record = new stdClass();
192         $record->course = $course->id;
193         $record->name = "Mod data delete test";
194         $record->intro = "Some intro of some sort";
195         $record->comments = 1;
197         $module = $this->getDataGenerator()->create_module('data', $record);
198         $field = data_get_field_new('text', $module);
200         $fielddetail = new stdClass();
201         $fielddetail->name = 'Name';
202         $fielddetail->description = 'Some name';
204         $field->define_field($fielddetail);
205         $field->insert_field();
206         $recordid = data_add_record($module);
208         $datacontent = array();
209         $datacontent['fieldid'] = $field->field->id;
210         $datacontent['recordid'] = $recordid;
211         $datacontent['content'] = 'Asterix';
213         $contentid = $DB->insert_record('data_content', $datacontent);
214         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
216         $context = context_module::instance($module->cmid);
217         $cmt = new stdClass();
218         $cmt->context = $context;
219         $cmt->course = $course;
220         $cmt->cm = $cm;
221         $cmt->area = 'database_entry';
222         $cmt->itemid = $recordid;
223         $cmt->showcount = true;
224         $cmt->component = 'mod_data';
225         $comment = new comment($cmt);
227         // Triggering and capturing the event.
228         $sink = $this->redirectEvents();
229         $comment->add('New comment');
230         $events = $sink->get_events();
231         $this->assertCount(1, $events);
232         $event = reset($events);
234         // Checking that the event contains the expected values.
235         $this->assertInstanceOf('\mod_data\event\comment_created', $event);
236         $this->assertEquals($context, $event->get_context());
237         $url = new moodle_url('/mod/data/view.php', array('id' => $cm->id));
238         $this->assertEquals($url, $event->get_url());
239         $this->assertEventContextNotUsed($event);
240     }
242     /**
243      * Test comment_deleted event.
244      */
245     public function test_data_comment_deleted_event() {
246         global $CFG, $DB;
247         require_once($CFG->dirroot . '/comment/lib.php');
249         $this->resetAfterTest();
251         // Create a record for deleting.
252         $this->setAdminUser();
253         $course = $this->getDataGenerator()->create_course();
254         $record = new stdClass();
255         $record->course = $course->id;
256         $record->name = "Mod data delete test";
257         $record->intro = "Some intro of some sort";
258         $record->comments = 1;
260         $module = $this->getDataGenerator()->create_module('data', $record);
261         $field = data_get_field_new('text', $module);
263         $fielddetail = new stdClass();
264         $fielddetail->name = 'Name';
265         $fielddetail->description = 'Some name';
267         $field->define_field($fielddetail);
268         $field->insert_field();
269         $recordid = data_add_record($module);
271         $datacontent = array();
272         $datacontent['fieldid'] = $field->field->id;
273         $datacontent['recordid'] = $recordid;
274         $datacontent['content'] = 'Asterix';
276         $contentid = $DB->insert_record('data_content', $datacontent);
277         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
279         $context = context_module::instance($module->cmid);
280         $cmt = new stdClass();
281         $cmt->context = $context;
282         $cmt->course = $course;
283         $cmt->cm = $cm;
284         $cmt->area = 'database_entry';
285         $cmt->itemid = $recordid;
286         $cmt->showcount = true;
287         $cmt->component = 'mod_data';
288         $comment = new comment($cmt);
289         $newcomment = $comment->add('New comment 1');
291         // Triggering and capturing the event.
292         $sink = $this->redirectEvents();
293         $comment->delete($newcomment->id);
294         $events = $sink->get_events();
295         $this->assertCount(1, $events);
296         $event = reset($events);
298         // Checking that the event contains the expected values.
299         $this->assertInstanceOf('\mod_data\event\comment_deleted', $event);
300         $this->assertEquals($context, $event->get_context());
301         $url = new moodle_url('/mod/data/view.php', array('id' => $module->cmid));
302         $this->assertEquals($url, $event->get_url());
303         $this->assertEventContextNotUsed($event);
304     }
306     /**
307      * Checks that data_user_can_manage_entry will return true if the user
308      * has the mod/data:manageentries capability.
309      */
310     public function test_data_user_can_manage_entry_return_true_with_capability() {
312         $this->resetAfterTest();
313         $testdata = $this->create_user_test_data();
315         $user = $testdata['user'];
316         $course = $testdata['course'];
317         $roleid = $testdata['roleid'];
318         $context = $testdata['context'];
319         $record = $testdata['record'];
320         $data = new stdClass();
322         $this->setUser($user);
324         assign_capability('mod/data:manageentries', CAP_ALLOW, $roleid, $context);
326         $this->assertTrue(data_user_can_manage_entry($record, $data, $context),
327             'data_user_can_manage_entry() returns true if the user has mod/data:manageentries capability');
328     }
330     /**
331      * Checks that data_user_can_manage_entry will return false if the data
332      * is set to readonly.
333      */
334     public function test_data_user_can_manage_entry_return_false_readonly() {
336         $this->resetAfterTest();
337         $testdata = $this->create_user_test_data();
339         $user = $testdata['user'];
340         $course = $testdata['course'];
341         $roleid = $testdata['roleid'];
342         $context = $testdata['context'];
343         $record = $testdata['record'];
345         $this->setUser($user);
347         // Need to make sure they don't have this capability in order to fall back to
348         // the other checks.
349         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
351         // Causes readonly mode to be enabled.
352         $data = new stdClass();
353         $now = time();
354         // Add a small margin around the periods to prevent errors with slow tests.
355         $data->timeviewfrom = $now - 1;
356         $data->timeviewto = $now + 5;
358         $this->assertFalse(data_user_can_manage_entry($record, $data, $context),
359             'data_user_can_manage_entry() returns false if the data is read only');
360     }
362     /**
363      * Checks that data_user_can_manage_entry will return false if the record
364      * can't be found in the database.
365      */
366     public function test_data_user_can_manage_entry_return_false_no_record() {
368         $this->resetAfterTest();
369         $testdata = $this->create_user_test_data();
371         $user = $testdata['user'];
372         $course = $testdata['course'];
373         $roleid = $testdata['roleid'];
374         $context = $testdata['context'];
375         $record = $testdata['record'];
376         $data = new stdClass();
377         // Causes readonly mode to be disabled.
378         $now = time();
379         $data->timeviewfrom = $now + 100;
380         $data->timeviewto = $now - 100;
382         $this->setUser($user);
384         // Need to make sure they don't have this capability in order to fall back to
385         // the other checks.
386         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
388         // Pass record id instead of object to force DB lookup.
389         $this->assertFalse(data_user_can_manage_entry(1, $data, $context),
390             'data_user_can_manage_entry() returns false if the record cannot be found');
391     }
393     /**
394      * Checks that data_user_can_manage_entry will return false if the record
395      * isn't owned by the user.
396      */
397     public function test_data_user_can_manage_entry_return_false_not_owned_record() {
399         $this->resetAfterTest();
400         $testdata = $this->create_user_test_data();
402         $user = $testdata['user'];
403         $course = $testdata['course'];
404         $roleid = $testdata['roleid'];
405         $context = $testdata['context'];
406         $record = $testdata['record'];
407         $data = new stdClass();
408         // Causes readonly mode to be disabled.
409         $now = time();
410         $data->timeviewfrom = $now + 100;
411         $data->timeviewto = $now - 100;
412         // Make sure the record isn't owned by this user.
413         $record->userid = $user->id + 1;
415         $this->setUser($user);
417         // Need to make sure they don't have this capability in order to fall back to
418         // the other checks.
419         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
421         $this->assertFalse(data_user_can_manage_entry($record, $data, $context),
422             'data_user_can_manage_entry() returns false if the record isnt owned by the user');
423     }
425     /**
426      * Checks that data_user_can_manage_entry will return true if the data
427      * doesn't require approval.
428      */
429     public function test_data_user_can_manage_entry_return_true_data_no_approval() {
431         $this->resetAfterTest();
432         $testdata = $this->create_user_test_data();
434         $user = $testdata['user'];
435         $course = $testdata['course'];
436         $roleid = $testdata['roleid'];
437         $context = $testdata['context'];
438         $record = $testdata['record'];
439         $data = new stdClass();
440         // Causes readonly mode to be disabled.
441         $now = time();
442         $data->timeviewfrom = $now + 100;
443         $data->timeviewto = $now - 100;
444         // The record doesn't need approval.
445         $data->approval = false;
446         // Make sure the record is owned by this user.
447         $record->userid = $user->id;
449         $this->setUser($user);
451         // Need to make sure they don't have this capability in order to fall back to
452         // the other checks.
453         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
455         $this->assertTrue(data_user_can_manage_entry($record, $data, $context),
456             'data_user_can_manage_entry() returns true if the record doesnt require approval');
457     }
459     /**
460      * Checks that data_user_can_manage_entry will return true if the record
461      * isn't yet approved.
462      */
463     public function test_data_user_can_manage_entry_return_true_record_unapproved() {
465         $this->resetAfterTest();
466         $testdata = $this->create_user_test_data();
468         $user = $testdata['user'];
469         $course = $testdata['course'];
470         $roleid = $testdata['roleid'];
471         $context = $testdata['context'];
472         $record = $testdata['record'];
473         $data = new stdClass();
474         // Causes readonly mode to be disabled.
475         $now = time();
476         $data->timeviewfrom = $now + 100;
477         $data->timeviewto = $now - 100;
478         // The record needs approval.
479         $data->approval = true;
480         // Make sure the record is owned by this user.
481         $record->userid = $user->id;
482         // The record hasn't yet been approved.
483         $record->approved = false;
485         $this->setUser($user);
487         // Need to make sure they don't have this capability in order to fall back to
488         // the other checks.
489         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
491         $this->assertTrue(data_user_can_manage_entry($record, $data, $context),
492             'data_user_can_manage_entry() returns true if the record is not yet approved');
493     }
495     /**
496      * Checks that data_user_can_manage_entry will return the 'manageapproved'
497      * value if the record has already been approved.
498      */
499     public function test_data_user_can_manage_entry_return_manageapproved() {
501         $this->resetAfterTest();
502         $testdata = $this->create_user_test_data();
504         $user = $testdata['user'];
505         $course = $testdata['course'];
506         $roleid = $testdata['roleid'];
507         $context = $testdata['context'];
508         $record = $testdata['record'];
509         $data = new stdClass();
510         // Causes readonly mode to be disabled.
511         $now = time();
512         $data->timeviewfrom = $now + 100;
513         $data->timeviewto = $now - 100;
514         // The record needs approval.
515         $data->approval = true;
516         // Can the user managed approved records?
517         $data->manageapproved = false;
518         // Make sure the record is owned by this user.
519         $record->userid = $user->id;
520         // The record has been approved.
521         $record->approved = true;
523         $this->setUser($user);
525         // Need to make sure they don't have this capability in order to fall back to
526         // the other checks.
527         assign_capability('mod/data:manageentries', CAP_PROHIBIT, $roleid, $context);
529         $canmanageentry = data_user_can_manage_entry($record, $data, $context);
531         // Make sure the result of the check is what ever the manageapproved setting
532         // is set to.
533         $this->assertEquals($data->manageapproved, $canmanageentry,
534             'data_user_can_manage_entry() returns the manageapproved setting on approved records');
535     }
537     /**
538      * Helper method to create a set of test data for data_user_can_manage tests
539      *
540      * @return array contains user, course, roleid, module, context and record
541      */
542     private function create_user_test_data() {
543         $user = $this->getDataGenerator()->create_user();
544         $course = $this->getDataGenerator()->create_course();
545         $roleid = $this->getDataGenerator()->create_role();
546         $record = new stdClass();
547         $record->name = "test name";
548         $record->intro = "test intro";
549         $record->comments = 1;
550         $record->course = $course->id;
551         $record->userid = $user->id;
553         $module = $this->getDataGenerator()->create_module('data', $record);
554         $cm = get_coursemodule_from_instance('data', $module->id, $course->id);
555         $context = context_module::instance($module->cmid);
557         $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id);
559         return array(
560             'user' => $user,
561             'course' => $course,
562             'roleid' => $roleid,
563             'module' => $module,
564             'context' => $context,
565             'record' => $record
566         );
567     }
569     /**
570      * Tests for mod_data_rating_can_see_item_ratings().
571      *
572      * @throws coding_exception
573      * @throws rating_exception
574      */
575     public function test_mod_data_rating_can_see_item_ratings() {
576         global $DB;
578         $this->resetAfterTest();
580         // Setup test data.
581         $course = new stdClass();
582         $course->groupmode = SEPARATEGROUPS;
583         $course->groupmodeforce = true;
584         $course = $this->getDataGenerator()->create_course($course);
585         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id));
586         $cm = get_coursemodule_from_instance('data', $data->id);
587         $context = context_module::instance($cm->id);
589         // Create users.
590         $user1 = $this->getDataGenerator()->create_user();
591         $user2 = $this->getDataGenerator()->create_user();
592         $user3 = $this->getDataGenerator()->create_user();
593         $user4 = $this->getDataGenerator()->create_user();
595         // Groups and stuff.
596         $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
597         $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id);
598         $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id);
599         $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id);
600         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id);
602         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
603         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
604         groups_add_member($group1, $user1);
605         groups_add_member($group1, $user2);
606         groups_add_member($group2, $user3);
607         groups_add_member($group2, $user4);
609         // Add data.
610         $field = data_get_field_new('text', $data);
612         $fielddetail = new stdClass();
613         $fielddetail->name = 'Name';
614         $fielddetail->description = 'Some name';
616         $field->define_field($fielddetail);
617         $field->insert_field();
619         // Add a record with a group id of zero (all participants).
620         $recordid1 = data_add_record($data, 0);
622         $datacontent = array();
623         $datacontent['fieldid'] = $field->field->id;
624         $datacontent['recordid'] = $recordid1;
625         $datacontent['content'] = 'Obelix';
626         $DB->insert_record('data_content', $datacontent);
628         $recordid = data_add_record($data, $group1->id);
630         $datacontent = array();
631         $datacontent['fieldid'] = $field->field->id;
632         $datacontent['recordid'] = $recordid;
633         $datacontent['content'] = 'Asterix';
634         $DB->insert_record('data_content', $datacontent);
636         // Now try to access it as various users.
637         unassign_capability('moodle/site:accessallgroups', $role->id);
638         // Eveyone should have access to the record with the group id of zero.
639         $params1 = array('contextid' => 2,
640                         'component' => 'mod_data',
641                         'ratingarea' => 'entry',
642                         'itemid' => $recordid1,
643                         'scaleid' => 2);
645         $params = array('contextid' => 2,
646                         'component' => 'mod_data',
647                         'ratingarea' => 'entry',
648                         'itemid' => $recordid,
649                         'scaleid' => 2);
651         $this->setUser($user1);
652         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
653         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
654         $this->setUser($user2);
655         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
656         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
657         $this->setUser($user3);
658         $this->assertFalse(mod_data_rating_can_see_item_ratings($params));
659         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
660         $this->setUser($user4);
661         $this->assertFalse(mod_data_rating_can_see_item_ratings($params));
662         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
664         // Now try with accessallgroups cap and make sure everything is visible.
665         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id);
666         $this->setUser($user1);
667         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
668         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
669         $this->setUser($user2);
670         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
671         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
672         $this->setUser($user3);
673         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
674         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
675         $this->setUser($user4);
676         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
677         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
679         // Change group mode and verify visibility.
680         $course->groupmode = VISIBLEGROUPS;
681         $DB->update_record('course', $course);
682         unassign_capability('moodle/site:accessallgroups', $role->id);
683         $this->setUser($user1);
684         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
685         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
686         $this->setUser($user2);
687         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
688         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
689         $this->setUser($user3);
690         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
691         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
692         $this->setUser($user4);
693         $this->assertTrue(mod_data_rating_can_see_item_ratings($params));
694         $this->assertTrue(mod_data_rating_can_see_item_ratings($params1));
696     }
698     /**
699      * Tests for mod_data_refresh_events.
700      */
701     public function test_data_refresh_events() {
702         global $DB;
703         $this->resetAfterTest();
704         $this->setAdminUser();
706         $timeopen = time();
707         $timeclose = time() + 86400;
709         $course = $this->getDataGenerator()->create_course();
710         $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
711         $params['course'] = $course->id;
712         $params['timeavailablefrom'] = $timeopen;
713         $params['timeavailableto'] = $timeclose;
714         $data = $generator->create_instance($params);
716         // Normal case, with existing course.
717         $this->assertTrue(data_refresh_events($course->id));
718         $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'open');
719         $openevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
720         $this->assertEquals($openevent->timestart, $timeopen);
722         $eventparams = array('modulename' => 'data', 'instance' => $data->id, 'eventtype' => 'close');
723         $closeevent = $DB->get_record('event', $eventparams, '*', MUST_EXIST);
724         $this->assertEquals($closeevent->timestart, $timeclose);
725         // In case the course ID is passed as a numeric string.
726         $this->assertTrue(data_refresh_events('' . $course->id));
727         // Course ID not provided.
728         $this->assertTrue(data_refresh_events());
729         $eventparams = array('modulename' => 'data');
730         $events = $DB->get_records('event', $eventparams);
731         foreach ($events as $event) {
732             if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'open') {
733                 $this->assertEquals($event->timestart, $timeopen);
734             }
735             if ($event->modulename === 'data' && $event->instance === $data->id && $event->eventtype === 'close') {
736                 $this->assertEquals($event->timestart, $timeclose);
737             }
738         }
739     }
741     /**
742      * Data provider for tests of data_get_config.
743      *
744      * @return array
745      */
746     public function data_get_config_provider() {
747         $initialdata = (object) [
748             'template_foo' => true,
749             'template_bar' => false,
750             'template_baz' => null,
751         ];
753         $database = (object) [
754             'config' => json_encode($initialdata),
755         ];
757         return [
758             'Return full dataset (no key/default)' => [
759                 [$database],
760                 $initialdata,
761             ],
762             'Return full dataset (no default)' => [
763                 [$database, null],
764                 $initialdata,
765             ],
766             'Return full dataset' => [
767                 [$database, null, null],
768                 $initialdata,
769             ],
770             'Return requested key only, value true, no default' => [
771                 [$database, 'template_foo'],
772                 true,
773             ],
774             'Return requested key only, value false, no default' => [
775                 [$database, 'template_bar'],
776                 false,
777             ],
778             'Return requested key only, value null, no default' => [
779                 [$database, 'template_baz'],
780                 null,
781             ],
782             'Return unknown key, value null, no default' => [
783                 [$database, 'template_bum'],
784                 null,
785             ],
786             'Return requested key only, value true, default null' => [
787                 [$database, 'template_foo', null],
788                 true,
789             ],
790             'Return requested key only, value false, default null' => [
791                 [$database, 'template_bar', null],
792                 false,
793             ],
794             'Return requested key only, value null, default null' => [
795                 [$database, 'template_baz', null],
796                 null,
797             ],
798             'Return unknown key, value null, default null' => [
799                 [$database, 'template_bum', null],
800                 null,
801             ],
802             'Return requested key only, value true, default 42' => [
803                 [$database, 'template_foo', 42],
804                 true,
805             ],
806             'Return requested key only, value false, default 42' => [
807                 [$database, 'template_bar', 42],
808                 false,
809             ],
810             'Return requested key only, value null, default 42' => [
811                 [$database, 'template_baz', 42],
812                 null,
813             ],
814             'Return unknown key, value null, default 42' => [
815                 [$database, 'template_bum', 42],
816                 42,
817             ],
818         ];
819     }
821     /**
822      * Tests for data_get_config.
823      *
824      * @dataProvider    data_get_config_provider
825      * @param   array   $funcargs       The args to pass to data_get_config
826      * @param   mixed   $expectation    The expected value
827      */
828     public function test_data_get_config($funcargs, $expectation) {
829         $this->assertEquals($expectation, call_user_func_array('data_get_config', $funcargs));
830     }
832     /**
833      * Data provider for tests of data_set_config.
834      *
835      * @return array
836      */
837     public function data_set_config_provider() {
838         $basevalue = (object) ['id' => rand(1, 1000)];
839         $config = [
840             'template_foo'  => true,
841             'template_bar'  => false,
842         ];
844         $withvalues = clone $basevalue;
845         $withvalues->config = json_encode((object) $config);
847         return [
848             'Empty config, New value' => [
849                 $basevalue,
850                 'etc',
851                 'newvalue',
852                 true,
853                 json_encode((object) ['etc' => 'newvalue'])
854             ],
855             'Has config, New value' => [
856                 clone $withvalues,
857                 'etc',
858                 'newvalue',
859                 true,
860                 json_encode((object) array_merge($config, ['etc' => 'newvalue']))
861             ],
862             'Has config, Update value, string' => [
863                 clone $withvalues,
864                 'template_foo',
865                 'newvalue',
866                 true,
867                 json_encode((object) array_merge($config, ['template_foo' => 'newvalue']))
868             ],
869             'Has config, Update value, true' => [
870                 clone $withvalues,
871                 'template_bar',
872                 true,
873                 true,
874                 json_encode((object) array_merge($config, ['template_bar' => true]))
875             ],
876             'Has config, Update value, false' => [
877                 clone $withvalues,
878                 'template_foo',
879                 false,
880                 true,
881                 json_encode((object) array_merge($config, ['template_foo' => false]))
882             ],
883             'Has config, Update value, null' => [
884                 clone $withvalues,
885                 'template_foo',
886                 null,
887                 true,
888                 json_encode((object) array_merge($config, ['template_foo' => null]))
889             ],
890             'Has config, No update, value true' => [
891                 clone $withvalues,
892                 'template_foo',
893                 true,
894                 false,
895                 $withvalues->config,
896             ],
897         ];
898     }
900     /**
901      * Tests for data_set_config.
902      *
903      * @dataProvider    data_set_config_provider
904      * @param   object  $database       The example row for the entry
905      * @param   string  $key            The config key to set
906      * @param   mixed   $value          The value of the key
907      * @param   bool    $expectupdate   Whether we expected an update
908      * @param   mixed   $newconfigvalue The expected value
909      */
910     public function test_data_set_config($database, $key, $value, $expectupdate, $newconfigvalue) {
911         global $DB;
913         // Mock the database.
914         // Note: Use the actual test class here rather than the abstract because are testing concrete methods.
915         $this->DB = $DB;
916         $DB = $this->getMockBuilder(get_class($DB))
917             ->setMethods(['set_field'])
918             ->getMock();
920         $DB->expects($this->exactly((int) $expectupdate))
921             ->method('set_field')
922             ->with(
923                 'data',
924                 'config',
925                 $newconfigvalue,
926                 ['id' => $database->id]
927             );
929         // Perform the update.
930         data_set_config($database, $key, $value);
932         // Ensure that the value was updated by reference in $database.
933         $config = json_decode($database->config);
934         $this->assertEquals($value, $config->$key);
935     }
937     /**
938      * Test data_view
939      * @return void
940      */
941     public function test_data_view() {
942         global $CFG;
944         $CFG->enablecompletion = 1;
945         $this->resetAfterTest();
947         $this->setAdminUser();
948         // Setup test data.
949         $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
950         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id),
951                                                             array('completion' => 2, 'completionview' => 1));
952         $context = context_module::instance($data->cmid);
953         $cm = get_coursemodule_from_instance('data', $data->id);
955         // Trigger and capture the event.
956         $sink = $this->redirectEvents();
958         data_view($data, $course, $cm, $context);
960         $events = $sink->get_events();
961         // 2 additional events thanks to completion.
962         $this->assertCount(3, $events);
963         $event = array_shift($events);
965         // Checking that the event contains the expected values.
966         $this->assertInstanceOf('\mod_data\event\course_module_viewed', $event);
967         $this->assertEquals($context, $event->get_context());
968         $moodleurl = new \moodle_url('/mod/data/view.php', array('id' => $cm->id));
969         $this->assertEquals($moodleurl, $event->get_url());
970         $this->assertEventContextNotUsed($event);
971         $this->assertNotEmpty($event->get_name());
973         // Check completion status.
974         $completion = new completion_info($course);
975         $completiondata = $completion->get_data($cm);
976         $this->assertEquals(1, $completiondata->completionstate);
977     }
979     public function test_mod_data_get_tagged_records() {
980         $this->resetAfterTest();
981         $this->setAdminUser();
983         // Setup test data.
984         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
985         $course1 = $this->getDataGenerator()->create_course();
987         $fieldrecord = new StdClass();
988         $fieldrecord->name = 'field-1';
989         $fieldrecord->type = 'text';
991         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
992         $field1 = $datagenerator->create_field($fieldrecord, $data1);
994         $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
995         $datagenerator->create_entry($data1, [$field1->field->id => 'value12'], 0, ['Cats', 'mice']);
996         $datagenerator->create_entry($data1, [$field1->field->id => 'value13'], 0, ['Cats']);
997         $datagenerator->create_entry($data1, [$field1->field->id => 'value14'], 0);
999         $tag = core_tag_tag::get_by_name(0, 'Cats');
1001         // Admin can see everything.
1002         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1003         $this->assertContains('value11', $res->content);
1004         $this->assertContains('value12', $res->content);
1005         $this->assertContains('value13', $res->content);
1006         $this->assertNotContains('value14', $res->content);
1007     }
1009     public function test_mod_data_get_tagged_records_approval() {
1010         global $DB;
1012         $this->resetAfterTest();
1013         $this->setAdminUser();
1015         // Setup test data.
1016         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
1017         $course2 = $this->getDataGenerator()->create_course();
1018         $course1 = $this->getDataGenerator()->create_course();
1020         $fieldrecord = new StdClass();
1021         $fieldrecord->name = 'field-1';
1022         $fieldrecord->type = 'text';
1024         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id));
1025         $field1 = $datagenerator->create_field($fieldrecord, $data1);
1026         $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id, 'approval' => true));
1027         $field2 = $datagenerator->create_field($fieldrecord, $data2);
1029         $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
1030         $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats'], ['approved' => false]);
1031         $tag = core_tag_tag::get_by_name(0, 'Cats');
1033         // Admin can see everything.
1034         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1035         $this->assertContains('value11', $res->content);
1036         $this->assertContains('value21', $res->content);
1037         $this->assertEmpty($res->prevpageurl);
1038         $this->assertEmpty($res->nextpageurl);
1040         // Create and enrol a user.
1041         $student = self::getDataGenerator()->create_user();
1042         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1043         $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
1044         $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
1045         $this->setUser($student);
1047         // User can search data records inside a course.
1048         core_tag_index_builder::reset_caches();
1049         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1051         $this->assertContains('value11', $res->content);
1052         $this->assertNotContains('value21', $res->content);
1054         $recordtoupdate = new stdClass();
1055         $recordtoupdate->id = $record21;
1056         $recordtoupdate->approved = true;
1057         $DB->update_record('data_records', $recordtoupdate);
1059         core_tag_index_builder::reset_caches();
1060         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1062         $this->assertContains('value11', $res->content);
1063         $this->assertContains('value21', $res->content);
1064     }
1066     public function test_mod_data_get_tagged_records_time() {
1067         global $DB;
1069         $this->resetAfterTest();
1070         $this->setAdminUser();
1072         // Setup test data.
1073         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
1074         $course2 = $this->getDataGenerator()->create_course();
1075         $course1 = $this->getDataGenerator()->create_course();
1077         $fieldrecord = new StdClass();
1078         $fieldrecord->name = 'field-1';
1079         $fieldrecord->type = 'text';
1081         $timefrom = time() - YEARSECS;
1082         $timeto = time() - WEEKSECS;
1084         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
1085         $field1 = $datagenerator->create_field($fieldrecord, $data1);
1086         $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id,
1087                                                                         'timeviewfrom' => $timefrom,
1088                                                                         'timeviewto'   => $timeto));
1089         $field2 = $datagenerator->create_field($fieldrecord, $data2);
1090         $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
1091         $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']);
1092         $tag = core_tag_tag::get_by_name(0, 'Cats');
1094         // Admin can see everything.
1095         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1096         $this->assertContains('value11', $res->content);
1097         $this->assertContains('value21', $res->content);
1098         $this->assertEmpty($res->prevpageurl);
1099         $this->assertEmpty($res->nextpageurl);
1101         // Create and enrol a user.
1102         $student = self::getDataGenerator()->create_user();
1103         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1104         $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
1105         $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
1106         $this->setUser($student);
1108         // User can search data records inside a course.
1109         core_tag_index_builder::reset_caches();
1110         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1112         $this->assertContains('value11', $res->content);
1113         $this->assertNotContains('value21', $res->content);
1115         $data2->timeviewto = time() + YEARSECS;
1116         $DB->update_record('data', $data2);
1118         core_tag_index_builder::reset_caches();
1119         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1121         $this->assertContains('value11', $res->content);
1122         $this->assertContains('value21', $res->content);
1123     }
1125     public function test_mod_data_get_tagged_records_course_enrolment() {
1126         global $DB;
1128         $this->resetAfterTest();
1129         $this->setAdminUser();
1131         // Setup test data.
1132         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
1133         $course2 = $this->getDataGenerator()->create_course();
1134         $course1 = $this->getDataGenerator()->create_course();
1136         $fieldrecord = new StdClass();
1137         $fieldrecord->name = 'field-1';
1138         $fieldrecord->type = 'text';
1140         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
1141         $field1 = $datagenerator->create_field($fieldrecord, $data1);
1142         $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id));
1143         $field2 = $datagenerator->create_field($fieldrecord, $data2);
1145         $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'], 0, ['Cats', 'Dogs']);
1146         $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'], 0, ['Cats']);
1147         $tag = core_tag_tag::get_by_name(0, 'Cats');
1149         // Admin can see everything.
1150         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1151         $this->assertContains('value11', $res->content);
1152         $this->assertContains('value21', $res->content);
1153         $this->assertEmpty($res->prevpageurl);
1154         $this->assertEmpty($res->nextpageurl);
1156         // Create and enrol a user.
1157         $student = self::getDataGenerator()->create_user();
1158         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1159         $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
1160         $this->setUser($student);
1161         core_tag_index_builder::reset_caches();
1163         // User can search data records inside a course.
1164         $coursecontext = context_course::instance($course1->id);
1165         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1167         $this->assertContains('value11', $res->content);
1168         $this->assertNotContains('value21', $res->content);
1170         $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
1172         core_tag_index_builder::reset_caches();
1173         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1175         $this->assertContains('value11', $res->content);
1176         $this->assertContains('value21', $res->content);
1177     }
1179     public function test_mod_data_get_tagged_records_course_groups() {
1180         global $DB;
1182         $this->resetAfterTest();
1183         $this->setAdminUser();
1185         // Setup test data.
1186         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
1187         $course2 = $this->getDataGenerator()->create_course();
1188         $course1 = $this->getDataGenerator()->create_course();
1190         $groupa = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupA'));
1191         $groupb = $this->getDataGenerator()->create_group(array('courseid' => $course2->id, 'name' => 'groupB'));
1193         $fieldrecord = new StdClass();
1194         $fieldrecord->name = 'field-1';
1195         $fieldrecord->type = 'text';
1197         $data1 = $this->getDataGenerator()->create_module('data', array('course' => $course1->id, 'approval' => true));
1198         $field1 = $datagenerator->create_field($fieldrecord, $data1);
1199         $data2 = $this->getDataGenerator()->create_module('data', array('course' => $course2->id));
1200         $field2 = $datagenerator->create_field($fieldrecord, $data2);
1201         set_coursemodule_groupmode($data2->cmid, SEPARATEGROUPS);
1203         $record11 = $datagenerator->create_entry($data1, [$field1->field->id => 'value11'],
1204                 0, ['Cats', 'Dogs']);
1205         $record21 = $datagenerator->create_entry($data2, [$field2->field->id => 'value21'],
1206                 $groupa->id, ['Cats']);
1207         $record22 = $datagenerator->create_entry($data2, [$field2->field->id => 'value22'],
1208                 $groupb->id, ['Cats']);
1209         $tag = core_tag_tag::get_by_name(0, 'Cats');
1211         // Admin can see everything.
1212         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1213         $this->assertContains('value11', $res->content);
1214         $this->assertContains('value21', $res->content);
1215         $this->assertContains('value22', $res->content);
1216         $this->assertEmpty($res->prevpageurl);
1217         $this->assertEmpty($res->nextpageurl);
1219         // Create and enrol a user.
1220         $student = self::getDataGenerator()->create_user();
1221         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1222         $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
1223         $this->getDataGenerator()->enrol_user($student->id, $course2->id, $studentrole->id, 'manual');
1224         groups_add_member($groupa, $student);
1225         $this->setUser($student);
1226         core_tag_index_builder::reset_caches();
1228         // User can search data records inside a course.
1229         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1231         $this->assertContains('value11', $res->content);
1232         $this->assertContains('value21', $res->content);
1233         $this->assertNotContains('value22', $res->content);
1235         groups_add_member($groupb, $student);
1236         core_tag_index_builder::reset_caches();
1237         $res = mod_data_get_tagged_records($tag, false, 0, 0, 1, 0);
1239         $this->assertContains('value11', $res->content);
1240         $this->assertContains('value21', $res->content);
1241         $this->assertContains('value22', $res->content);
1242     }
1244     /**
1245      * Test check_updates_since callback.
1246      */
1247     public function test_check_updates_since() {
1248         global $DB;
1249         $this->resetAfterTest();
1250         $this->setAdminUser();
1251         $course = $this->getDataGenerator()->create_course();
1252         // Create user.
1253         $student = self::getDataGenerator()->create_user();
1254         // User enrolment.
1255         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1256         $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
1257         $this->setCurrentTimeStart();
1258         $record = array(
1259             'course' => $course->id,
1260         );
1261         $data = $this->getDataGenerator()->create_module('data', $record);
1262         $cm = get_coursemodule_from_instance('data', $data->id, $course->id);
1263         $cm = cm_info::create($cm);
1264         $this->setUser($student);
1266         // Check that upon creation, the updates are only about the new configuration created.
1267         $onehourago = time() - HOURSECS;
1268         $updates = data_check_updates_since($cm, $onehourago);
1269         foreach ($updates as $el => $val) {
1270             if ($el == 'configuration') {
1271                 $this->assertTrue($val->updated);
1272                 $this->assertTimeCurrent($val->timeupdated);
1273             } else {
1274                 $this->assertFalse($val->updated);
1275             }
1276         }
1278         // Add a couple of entries.
1279         $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
1280         $fieldtypes = array('checkbox', 'date');
1282         $count = 1;
1283         // Creating test Fields with default parameter values.
1284         foreach ($fieldtypes as $fieldtype) {
1285             // Creating variables dynamically.
1286             $fieldname = 'field-' . $count;
1287             $record = new StdClass();
1288             $record->name = $fieldname;
1289             $record->type = $fieldtype;
1290             $record->required = 1;
1292             ${$fieldname} = $datagenerator->create_field($record, $data);
1293             $count++;
1294         }
1296         $fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id');
1298         $contents = array();
1299         $contents[] = array('opt1', 'opt2', 'opt3', 'opt4');
1300         $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows.
1301         $count = 0;
1302         $fieldcontents = array();
1303         foreach ($fields as $fieldrecord) {
1304             $fieldcontents[$fieldrecord->id] = $contents[$count++];
1305         }
1307         $datarecor1did = $datagenerator->create_entry($data, $fieldcontents);
1308         $datarecor2did = $datagenerator->create_entry($data, $fieldcontents);
1309         $records = $DB->get_records('data_records', array('dataid' => $data->id));
1310         $this->assertCount(2, $records);
1311         // Check we received the entries updated.
1312         $updates = data_check_updates_since($cm, $onehourago);
1313         $this->assertTrue($updates->entries->updated);
1314         $this->assertEquals([$datarecor1did, $datarecor2did], $updates->entries->itemids, '', 0, 10, true);
1315     }
1317     public function test_data_core_calendar_provide_event_action_open() {
1318         $this->resetAfterTest();
1320         $this->setAdminUser();
1322         // Create a course.
1323         $course = $this->getDataGenerator()->create_course();
1325         // Create a database activity.
1326         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id,
1327             'timeavailablefrom' => time() - DAYSECS, 'timeavailableto' => time() + DAYSECS));
1329         // Create a calendar event.
1330         $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN);
1332         // Create an action factory.
1333         $factory = new \core_calendar\action_factory();
1335         // Decorate action event.
1336         $actionevent = mod_data_core_calendar_provide_event_action($event, $factory);
1338         // Confirm the event was decorated.
1339         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
1340         $this->assertEquals(get_string('add', 'data'), $actionevent->get_name());
1341         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
1342         $this->assertEquals(1, $actionevent->get_item_count());
1343         $this->assertTrue($actionevent->is_actionable());
1344     }
1346     public function test_data_core_calendar_provide_event_action_closed() {
1347         $this->resetAfterTest();
1349         $this->setAdminUser();
1351         // Create a course.
1352         $course = $this->getDataGenerator()->create_course();
1354         // Create a database activity.
1355         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id,
1356             'timeavailableto' => time() - DAYSECS));
1358         // Create a calendar event.
1359         $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN);
1361         // Create an action factory.
1362         $factory = new \core_calendar\action_factory();
1364         // Decorate action event.
1365         $actionevent = mod_data_core_calendar_provide_event_action($event, $factory);
1367         // No event on the dashboard if module is closed.
1368         $this->assertNull($actionevent);
1369     }
1371     public function test_data_core_calendar_provide_event_action_open_in_future() {
1372         $this->resetAfterTest();
1374         $this->setAdminUser();
1376         // Create a course.
1377         $course = $this->getDataGenerator()->create_course();
1379         // Create a database activity.
1380         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id,
1381             'timeavailablefrom' => time() + DAYSECS));
1383         // Create a calendar event.
1384         $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN);
1386         // Create an action factory.
1387         $factory = new \core_calendar\action_factory();
1389         // Decorate action event.
1390         $actionevent = mod_data_core_calendar_provide_event_action($event, $factory);
1392         // Confirm the event was decorated.
1393         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
1394         $this->assertEquals(get_string('add', 'data'), $actionevent->get_name());
1395         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
1396         $this->assertEquals(1, $actionevent->get_item_count());
1397         $this->assertFalse($actionevent->is_actionable());
1398     }
1400     public function test_data_core_calendar_provide_event_action_no_time_specified() {
1401         $this->resetAfterTest();
1403         $this->setAdminUser();
1405         // Create a course.
1406         $course = $this->getDataGenerator()->create_course();
1408         // Create a database activity.
1409         $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id));
1411         // Create a calendar event.
1412         $event = $this->create_action_event($course->id, $data->id, DATA_EVENT_TYPE_OPEN);
1414         // Create an action factory.
1415         $factory = new \core_calendar\action_factory();
1417         // Decorate action event.
1418         $actionevent = mod_data_core_calendar_provide_event_action($event, $factory);
1420         // Confirm the event was decorated.
1421         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
1422         $this->assertEquals(get_string('add', 'data'), $actionevent->get_name());
1423         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
1424         $this->assertEquals(1, $actionevent->get_item_count());
1425         $this->assertTrue($actionevent->is_actionable());
1426     }
1428     /**
1429      * Creates an action event.
1430      *
1431      * @param int $courseid
1432      * @param int $instanceid The data id.
1433      * @param string $eventtype The event type. eg. DATA_EVENT_TYPE_OPEN.
1434      * @return bool|calendar_event
1435      */
1436     private function create_action_event($courseid, $instanceid, $eventtype) {
1437         $event = new stdClass();
1438         $event->name = 'Calendar event';
1439         $event->modulename  = 'data';
1440         $event->courseid = $courseid;
1441         $event->instance = $instanceid;
1442         $event->type = CALENDAR_EVENT_TYPE_ACTION;
1443         $event->eventtype = $eventtype;
1444         $event->timestart = time();
1446         return calendar_event::create($event);
1447     }
1449     /**
1450      * Test the callback responsible for returning the completion rule descriptions.
1451      * This function should work given either an instance of the module (cm_info), such as when checking the active rules,
1452      * or if passed a stdClass of similar structure, such as when checking the the default completion settings for a mod type.
1453      */
1454     public function test_mod_data_completion_get_active_rule_descriptions() {
1455         $this->resetAfterTest();
1456         $this->setAdminUser();
1458         // Two activities, both with automatic completion. One has the 'completionentries' rule, one doesn't.
1459         $course = $this->getDataGenerator()->create_course(['enablecompletion' => 2]);
1460         $data1 = $this->getDataGenerator()->create_module('data', [
1461             'course' => $course->id,
1462             'completion' => 2,
1463             'completionentries' => 3
1464         ]);
1465         $data2 = $this->getDataGenerator()->create_module('data', [
1466             'course' => $course->id,
1467             'completion' => 2,
1468             'completionentries' => 0
1469         ]);
1470         $cm1 = cm_info::create(get_coursemodule_from_instance('data', $data1->id));
1471         $cm2 = cm_info::create(get_coursemodule_from_instance('data', $data2->id));
1473         // Data for the stdClass input type.
1474         // This type of input would occur when checking the default completion rules for an activity type, where we don't have
1475         // any access to cm_info, rather the input is a stdClass containing completion and customdata attributes, just like cm_info.
1476         $moddefaults = new stdClass();
1477         $moddefaults->customdata = ['customcompletionrules' => ['completionentries' => 3]];
1478         $moddefaults->completion = 2;
1480         $activeruledescriptions = [get_string('completionentriesdesc', 'data', 3)];
1481         $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm1), $activeruledescriptions);
1482         $this->assertEquals(mod_data_get_completion_active_rule_descriptions($cm2), []);
1483         $this->assertEquals(mod_data_get_completion_active_rule_descriptions($moddefaults), $activeruledescriptions);
1484         $this->assertEquals(mod_data_get_completion_active_rule_descriptions(new stdClass()), []);
1485     }