weekly release 3.2dev
[moodle.git] / mod / assign / tests / externallib_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 defined('MOODLE_INTERNAL') || die();
19 global $CFG;
21 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
23 /**
24  * External mod assign functions unit tests
25  *
26  * @package mod_assign
27  * @category external
28  * @copyright 2012 Paul Charsley
29  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30  */
31 class mod_assign_external_testcase extends externallib_advanced_testcase {
33     /**
34      * Tests set up
35      */
36     protected function setUp() {
37         global $CFG;
38         require_once($CFG->dirroot . '/mod/assign/externallib.php');
39     }
41     /**
42      * Test get_grades
43      */
44     public function test_get_grades() {
45         global $DB, $USER;
47         $this->resetAfterTest(true);
48         // Create a course and assignment.
49         $coursedata['idnumber'] = 'idnumbercourse';
50         $coursedata['fullname'] = 'Lightwork Course';
51         $coursedata['summary'] = 'Lightwork Course description';
52         $coursedata['summaryformat'] = FORMAT_MOODLE;
53         $course = self::getDataGenerator()->create_course($coursedata);
55         $assigndata['course'] = $course->id;
56         $assigndata['name'] = 'lightwork assignment';
58         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
60         // Create a manual enrolment record.
61         $manualenroldata['enrol'] = 'manual';
62         $manualenroldata['status'] = 0;
63         $manualenroldata['courseid'] = $course->id;
64         $enrolid = $DB->insert_record('enrol', $manualenroldata);
66         // Create a teacher and give them capabilities.
67         $context = context_course::instance($course->id);
68         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
69         $context = context_module::instance($assign->cmid);
70         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
72         // Create the teacher's enrolment record.
73         $userenrolmentdata['status'] = 0;
74         $userenrolmentdata['enrolid'] = $enrolid;
75         $userenrolmentdata['userid'] = $USER->id;
76         $DB->insert_record('user_enrolments', $userenrolmentdata);
78         // Create a student and give them 2 grades (for 2 attempts).
79         $student = self::getDataGenerator()->create_user();
81         $submission = new stdClass();
82         $submission->assignment = $assign->id;
83         $submission->userid = $student->id;
84         $submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
85         $submission->latest = 0;
86         $submission->attemptnumber = 0;
87         $submission->groupid = 0;
88         $submission->timecreated = time();
89         $submission->timemodified = time();
90         $DB->insert_record('assign_submission', $submission);
92         $grade = new stdClass();
93         $grade->assignment = $assign->id;
94         $grade->userid = $student->id;
95         $grade->timecreated = time();
96         $grade->timemodified = $grade->timecreated;
97         $grade->grader = $USER->id;
98         $grade->grade = 50;
99         $grade->attemptnumber = 0;
100         $DB->insert_record('assign_grades', $grade);
102         $submission = new stdClass();
103         $submission->assignment = $assign->id;
104         $submission->userid = $student->id;
105         $submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
106         $submission->latest = 1;
107         $submission->attemptnumber = 1;
108         $submission->groupid = 0;
109         $submission->timecreated = time();
110         $submission->timemodified = time();
111         $DB->insert_record('assign_submission', $submission);
113         $grade = new stdClass();
114         $grade->assignment = $assign->id;
115         $grade->userid = $student->id;
116         $grade->timecreated = time();
117         $grade->timemodified = $grade->timecreated;
118         $grade->grader = $USER->id;
119         $grade->grade = 75;
120         $grade->attemptnumber = 1;
121         $DB->insert_record('assign_grades', $grade);
123         $assignmentids[] = $assign->id;
124         $result = mod_assign_external::get_grades($assignmentids);
126         // We need to execute the return values cleaning process to simulate the web service server.
127         $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result);
129         // Check that the correct grade information for the student is returned.
130         $this->assertEquals(1, count($result['assignments']));
131         $assignment = $result['assignments'][0];
132         $this->assertEquals($assign->id, $assignment['assignmentid']);
133         // Should only get the last grade for this student.
134         $this->assertEquals(1, count($assignment['grades']));
135         $grade = $assignment['grades'][0];
136         $this->assertEquals($student->id, $grade['userid']);
137         // Should be the last grade (not the first).
138         $this->assertEquals(75, $grade['grade']);
139     }
141     /**
142      * Test get_assignments
143      */
144     public function test_get_assignments() {
145         global $DB, $USER, $CFG;
147         $this->resetAfterTest(true);
149         $category = self::getDataGenerator()->create_category(array(
150             'name' => 'Test category'
151         ));
153         // Create a course.
154         $course1 = self::getDataGenerator()->create_course(array(
155             'idnumber' => 'idnumbercourse1',
156             'fullname' => 'Lightwork Course 1',
157             'summary' => 'Lightwork Course 1 description',
158             'summaryformat' => FORMAT_MOODLE,
159             'category' => $category->id
160         ));
162         // Create a second course, just for testing.
163         $course2 = self::getDataGenerator()->create_course(array(
164             'idnumber' => 'idnumbercourse2',
165             'fullname' => 'Lightwork Course 2',
166             'summary' => 'Lightwork Course 2 description',
167             'summaryformat' => FORMAT_MOODLE,
168             'category' => $category->id
169         ));
171         // Create the assignment module with links to a filerecord.
172         $assign1 = self::getDataGenerator()->create_module('assign', array(
173             'course' => $course1->id,
174             'name' => 'lightwork assignment',
175             'intro' => 'the assignment intro text here <a href="@@PLUGINFILE@@/intro.txt">link</a>',
176             'introformat' => FORMAT_HTML,
177             'markingworkflow' => 1,
178             'markingallocation' => 1
179         ));
181         // Add a file as assignment attachment.
182         $context = context_module::instance($assign1->cmid);
183         $filerecord = array('component' => 'mod_assign', 'filearea' => 'intro', 'contextid' => $context->id, 'itemid' => 0,
184                 'filename' => 'intro.txt', 'filepath' => '/');
185         $fs = get_file_storage();
186         $fs->create_file_from_string($filerecord, 'Test intro file');
188         // Create manual enrolment record.
189         $enrolid = $DB->insert_record('enrol', (object)array(
190             'enrol' => 'manual',
191             'status' => 0,
192             'courseid' => $course1->id
193         ));
195         // Create the user and give them capabilities.
196         $context = context_course::instance($course1->id);
197         $roleid = $this->assignUserCapability('moodle/course:view', $context->id);
198         $context = context_module::instance($assign1->cmid);
199         $this->assignUserCapability('mod/assign:view', $context->id, $roleid);
201         // Create the user enrolment record.
202         $DB->insert_record('user_enrolments', (object)array(
203             'status' => 0,
204             'enrolid' => $enrolid,
205             'userid' => $USER->id
206         ));
208         // Add a file as assignment attachment.
209         $filerecord = array('component' => 'mod_assign', 'filearea' => ASSIGN_INTROATTACHMENT_FILEAREA,
210                 'contextid' => $context->id, 'itemid' => 0,
211                 'filename' => 'introattachment.txt', 'filepath' => '/');
212         $fs = get_file_storage();
213         $fs->create_file_from_string($filerecord, 'Test intro attachment file');
215         $result = mod_assign_external::get_assignments();
217         // We need to execute the return values cleaning process to simulate the web service server.
218         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
220         // Check the course and assignment are returned.
221         $this->assertEquals(1, count($result['courses']));
222         $course = $result['courses'][0];
223         $this->assertEquals('Lightwork Course 1', $course['fullname']);
224         $this->assertEquals(1, count($course['assignments']));
225         $assignment = $course['assignments'][0];
226         $this->assertEquals($assign1->id, $assignment['id']);
227         $this->assertEquals($course1->id, $assignment['course']);
228         $this->assertEquals('lightwork assignment', $assignment['name']);
229         $this->assertContains('the assignment intro text here', $assignment['intro']);
230         // Check the url of the file attatched.
231         $this->assertRegExp('@"' . $CFG->wwwroot . '/webservice/pluginfile.php/\d+/mod_assign/intro/intro\.txt"@', $assignment['intro']);
232         $this->assertEquals(1, $assignment['markingworkflow']);
233         $this->assertEquals(1, $assignment['markingallocation']);
234         $this->assertEquals(0, $assignment['preventsubmissionnotingroup']);
236         $this->assertCount(1, $assignment['introattachments']);
237         $this->assertEquals('introattachment.txt', $assignment['introattachments'][0]['filename']);
239         // Now, hide the descritption until the submission from date.
240         $DB->set_field('assign', 'alwaysshowdescription', 0, array('id' => $assign1->id));
241         $DB->set_field('assign', 'allowsubmissionsfromdate', time() + DAYSECS, array('id' => $assign1->id));
243         $result = mod_assign_external::get_assignments(array($course1->id));
245         // We need to execute the return values cleaning process to simulate the web service server.
246         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
248         $this->assertEquals(1, count($result['courses']));
249         $course = $result['courses'][0];
250         $this->assertEquals('Lightwork Course 1', $course['fullname']);
251         $this->assertEquals(1, count($course['assignments']));
252         $assignment = $course['assignments'][0];
253         $this->assertEquals($assign1->id, $assignment['id']);
254         $this->assertEquals($course1->id, $assignment['course']);
255         $this->assertEquals('lightwork assignment', $assignment['name']);
256         $this->assertArrayNotHasKey('intro', $assignment);
257         $this->assertArrayNotHasKey('introattachments', $assignment);
258         $this->assertEquals(1, $assignment['markingworkflow']);
259         $this->assertEquals(1, $assignment['markingallocation']);
260         $this->assertEquals(0, $assignment['preventsubmissionnotingroup']);
262         $result = mod_assign_external::get_assignments(array($course2->id));
264         // We need to execute the return values cleaning process to simulate the web service server.
265         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
267         $this->assertEquals(0, count($result['courses']));
268         $this->assertEquals(1, count($result['warnings']));
270         // Test with non-enrolled user, but with view capabilities.
271         $this->setAdminUser();
272         $result = mod_assign_external::get_assignments();
273         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
274         $this->assertEquals(0, count($result['courses']));
275         $this->assertEquals(0, count($result['warnings']));
277         // Expect no courses, because we are not using the special flag.
278         $result = mod_assign_external::get_assignments(array($course1->id));
279         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
280         $this->assertCount(0, $result['courses']);
282         // Now use the special flag to return courses where you are not enroled in.
283         $result = mod_assign_external::get_assignments(array($course1->id), array(), true);
284         $result = external_api::clean_returnvalue(mod_assign_external::get_assignments_returns(), $result);
285         $this->assertCount(1, $result['courses']);
287         $course = $result['courses'][0];
288         $this->assertEquals('Lightwork Course 1', $course['fullname']);
289         $this->assertEquals(1, count($course['assignments']));
290         $assignment = $course['assignments'][0];
291         $this->assertEquals($assign1->id, $assignment['id']);
292         $this->assertEquals($course1->id, $assignment['course']);
293         $this->assertEquals('lightwork assignment', $assignment['name']);
294         $this->assertArrayNotHasKey('intro', $assignment);
295         $this->assertArrayNotHasKey('introattachments', $assignment);
296         $this->assertEquals(1, $assignment['markingworkflow']);
297         $this->assertEquals(1, $assignment['markingallocation']);
298         $this->assertEquals(0, $assignment['preventsubmissionnotingroup']);
299     }
301     /**
302      * Test get_submissions
303      */
304     public function test_get_submissions() {
305         global $DB, $USER;
307         $this->resetAfterTest(true);
308         // Create a course and assignment.
309         $coursedata['idnumber'] = 'idnumbercourse1';
310         $coursedata['fullname'] = 'Lightwork Course 1';
311         $coursedata['summary'] = 'Lightwork Course 1 description';
312         $coursedata['summaryformat'] = FORMAT_MOODLE;
313         $course1 = self::getDataGenerator()->create_course($coursedata);
315         $assigndata['course'] = $course1->id;
316         $assigndata['name'] = 'lightwork assignment';
318         $assign1 = self::getDataGenerator()->create_module('assign', $assigndata);
320         // Create a student with an online text submission.
321         // First attempt.
322         $student = self::getDataGenerator()->create_user();
323         $submission = new stdClass();
324         $submission->assignment = $assign1->id;
325         $submission->userid = $student->id;
326         $submission->timecreated = time();
327         $submission->timemodified = $submission->timecreated;
328         $submission->status = 'draft';
329         $submission->attemptnumber = 0;
330         $submission->latest = 0;
331         $sid = $DB->insert_record('assign_submission', $submission);
333         // Second attempt.
334         $submission = new stdClass();
335         $submission->assignment = $assign1->id;
336         $submission->userid = $student->id;
337         $submission->timecreated = time();
338         $submission->timemodified = $submission->timecreated;
339         $submission->status = 'submitted';
340         $submission->attemptnumber = 1;
341         $submission->latest = 1;
342         $sid = $DB->insert_record('assign_submission', $submission);
343         $submission->id = $sid;
345         $onlinetextsubmission = new stdClass();
346         $onlinetextsubmission->onlinetext = "<p>online test text</p>";
347         $onlinetextsubmission->onlineformat = 1;
348         $onlinetextsubmission->submission = $submission->id;
349         $onlinetextsubmission->assignment = $assign1->id;
350         $DB->insert_record('assignsubmission_onlinetext', $onlinetextsubmission);
352         // Create manual enrolment record.
353         $manualenroldata['enrol'] = 'manual';
354         $manualenroldata['status'] = 0;
355         $manualenroldata['courseid'] = $course1->id;
356         $enrolid = $DB->insert_record('enrol', $manualenroldata);
358         // Create a teacher and give them capabilities.
359         $context = context_course::instance($course1->id);
360         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
361         $context = context_module::instance($assign1->cmid);
362         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
364         // Create the teacher's enrolment record.
365         $userenrolmentdata['status'] = 0;
366         $userenrolmentdata['enrolid'] = $enrolid;
367         $userenrolmentdata['userid'] = $USER->id;
368         $DB->insert_record('user_enrolments', $userenrolmentdata);
370         $assignmentids[] = $assign1->id;
371         $result = mod_assign_external::get_submissions($assignmentids);
372         $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
374         // Check the online text submission is returned.
375         $this->assertEquals(1, count($result['assignments']));
376         $assignment = $result['assignments'][0];
377         $this->assertEquals($assign1->id, $assignment['assignmentid']);
378         $this->assertEquals(1, count($assignment['submissions']));
379         $submission = $assignment['submissions'][0];
380         $this->assertEquals($sid, $submission['id']);
381         $this->assertCount(1, $submission['plugins']);
382     }
384     /**
385      * Test get_user_flags
386      */
387     public function test_get_user_flags() {
388         global $DB, $USER;
390         $this->resetAfterTest(true);
391         // Create a course and assignment.
392         $coursedata['idnumber'] = 'idnumbercourse';
393         $coursedata['fullname'] = 'Lightwork Course';
394         $coursedata['summary'] = 'Lightwork Course description';
395         $coursedata['summaryformat'] = FORMAT_MOODLE;
396         $course = self::getDataGenerator()->create_course($coursedata);
398         $assigndata['course'] = $course->id;
399         $assigndata['name'] = 'lightwork assignment';
401         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
403         // Create a manual enrolment record.
404         $manualenroldata['enrol'] = 'manual';
405         $manualenroldata['status'] = 0;
406         $manualenroldata['courseid'] = $course->id;
407         $enrolid = $DB->insert_record('enrol', $manualenroldata);
409         // Create a teacher and give them capabilities.
410         $context = context_course::instance($course->id);
411         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
412         $context = context_module::instance($assign->cmid);
413         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
415         // Create the teacher's enrolment record.
416         $userenrolmentdata['status'] = 0;
417         $userenrolmentdata['enrolid'] = $enrolid;
418         $userenrolmentdata['userid'] = $USER->id;
419         $DB->insert_record('user_enrolments', $userenrolmentdata);
421         // Create a student and give them a user flag record.
422         $student = self::getDataGenerator()->create_user();
423         $userflag = new stdClass();
424         $userflag->assignment = $assign->id;
425         $userflag->userid = $student->id;
426         $userflag->locked = 0;
427         $userflag->mailed = 0;
428         $userflag->extensionduedate = 0;
429         $userflag->workflowstate = 'inmarking';
430         $userflag->allocatedmarker = $USER->id;
432         $DB->insert_record('assign_user_flags', $userflag);
434         $assignmentids[] = $assign->id;
435         $result = mod_assign_external::get_user_flags($assignmentids);
437         // We need to execute the return values cleaning process to simulate the web service server.
438         $result = external_api::clean_returnvalue(mod_assign_external::get_user_flags_returns(), $result);
440         // Check that the correct user flag information for the student is returned.
441         $this->assertEquals(1, count($result['assignments']));
442         $assignment = $result['assignments'][0];
443         $this->assertEquals($assign->id, $assignment['assignmentid']);
444         // Should be one user flag record.
445         $this->assertEquals(1, count($assignment['userflags']));
446         $userflag = $assignment['userflags'][0];
447         $this->assertEquals($student->id, $userflag['userid']);
448         $this->assertEquals(0, $userflag['locked']);
449         $this->assertEquals(0, $userflag['mailed']);
450         $this->assertEquals(0, $userflag['extensionduedate']);
451         $this->assertEquals('inmarking', $userflag['workflowstate']);
452         $this->assertEquals($USER->id, $userflag['allocatedmarker']);
453     }
455     /**
456      * Test get_user_mappings
457      */
458     public function test_get_user_mappings() {
459         global $DB, $USER;
461         $this->resetAfterTest(true);
462         // Create a course and assignment.
463         $coursedata['idnumber'] = 'idnumbercourse';
464         $coursedata['fullname'] = 'Lightwork Course';
465         $coursedata['summary'] = 'Lightwork Course description';
466         $coursedata['summaryformat'] = FORMAT_MOODLE;
467         $course = self::getDataGenerator()->create_course($coursedata);
469         $assigndata['course'] = $course->id;
470         $assigndata['name'] = 'lightwork assignment';
472         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
474         // Create a manual enrolment record.
475         $manualenroldata['enrol'] = 'manual';
476         $manualenroldata['status'] = 0;
477         $manualenroldata['courseid'] = $course->id;
478         $enrolid = $DB->insert_record('enrol', $manualenroldata);
480         // Create a teacher and give them capabilities.
481         $context = context_course::instance($course->id);
482         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
483         $context = context_module::instance($assign->cmid);
484         $this->assignUserCapability('mod/assign:revealidentities', $context->id, $roleid);
486         // Create the teacher's enrolment record.
487         $userenrolmentdata['status'] = 0;
488         $userenrolmentdata['enrolid'] = $enrolid;
489         $userenrolmentdata['userid'] = $USER->id;
490         $DB->insert_record('user_enrolments', $userenrolmentdata);
492         // Create a student and give them a user mapping record.
493         $student = self::getDataGenerator()->create_user();
494         $mapping = new stdClass();
495         $mapping->assignment = $assign->id;
496         $mapping->userid = $student->id;
498         $DB->insert_record('assign_user_mapping', $mapping);
500         $assignmentids[] = $assign->id;
501         $result = mod_assign_external::get_user_mappings($assignmentids);
503         // We need to execute the return values cleaning process to simulate the web service server.
504         $result = external_api::clean_returnvalue(mod_assign_external::get_user_mappings_returns(), $result);
506         // Check that the correct user mapping information for the student is returned.
507         $this->assertEquals(1, count($result['assignments']));
508         $assignment = $result['assignments'][0];
509         $this->assertEquals($assign->id, $assignment['assignmentid']);
510         // Should be one user mapping record.
511         $this->assertEquals(1, count($assignment['mappings']));
512         $mapping = $assignment['mappings'][0];
513         $this->assertEquals($student->id, $mapping['userid']);
514     }
516     /**
517      * Test lock_submissions
518      */
519     public function test_lock_submissions() {
520         global $DB, $USER;
522         $this->resetAfterTest(true);
523         // Create a course and assignment and users.
524         $course = self::getDataGenerator()->create_course();
526         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
527         $params['course'] = $course->id;
528         $params['assignsubmission_onlinetext_enabled'] = 1;
529         $instance = $generator->create_instance($params);
530         $cm = get_coursemodule_from_instance('assign', $instance->id);
531         $context = context_module::instance($cm->id);
533         $assign = new assign($context, $cm, $course);
535         $student1 = self::getDataGenerator()->create_user();
536         $student2 = self::getDataGenerator()->create_user();
537         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
538         $this->getDataGenerator()->enrol_user($student1->id,
539                                               $course->id,
540                                               $studentrole->id);
541         $this->getDataGenerator()->enrol_user($student2->id,
542                                               $course->id,
543                                               $studentrole->id);
544         $teacher = self::getDataGenerator()->create_user();
545         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
546         $this->getDataGenerator()->enrol_user($teacher->id,
547                                               $course->id,
548                                               $teacherrole->id);
550         // Create a student1 with an online text submission.
551         // Simulate a submission.
552         $this->setUser($student1);
553         $submission = $assign->get_user_submission($student1->id, true);
554         $data = new stdClass();
555         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
556                                          'text'=>'Submission text',
557                                          'format'=>FORMAT_MOODLE);
558         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
559         $plugin->save($submission, $data);
561         // Ready to test.
562         $this->setUser($teacher);
563         $students = array($student1->id, $student2->id);
564         $result = mod_assign_external::lock_submissions($instance->id, $students);
565         $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
567         // Check for 0 warnings.
568         $this->assertEquals(0, count($result));
570         $this->setUser($student2);
571         $submission = $assign->get_user_submission($student2->id, true);
572         $data = new stdClass();
573         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
574                                          'text'=>'Submission text',
575                                          'format'=>FORMAT_MOODLE);
576         $notices = array();
577         $this->setExpectedException('moodle_exception');
578         $assign->save_submission($data, $notices);
579     }
581     /**
582      * Test unlock_submissions
583      */
584     public function test_unlock_submissions() {
585         global $DB, $USER;
587         $this->resetAfterTest(true);
588         // Create a course and assignment and users.
589         $course = self::getDataGenerator()->create_course();
591         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
592         $params['course'] = $course->id;
593         $params['assignsubmission_onlinetext_enabled'] = 1;
594         $instance = $generator->create_instance($params);
595         $cm = get_coursemodule_from_instance('assign', $instance->id);
596         $context = context_module::instance($cm->id);
598         $assign = new assign($context, $cm, $course);
600         $student1 = self::getDataGenerator()->create_user();
601         $student2 = self::getDataGenerator()->create_user();
602         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
603         $this->getDataGenerator()->enrol_user($student1->id,
604                                               $course->id,
605                                               $studentrole->id);
606         $this->getDataGenerator()->enrol_user($student2->id,
607                                               $course->id,
608                                               $studentrole->id);
609         $teacher = self::getDataGenerator()->create_user();
610         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
611         $this->getDataGenerator()->enrol_user($teacher->id,
612                                               $course->id,
613                                               $teacherrole->id);
615         // Create a student1 with an online text submission.
616         // Simulate a submission.
617         $this->setUser($student1);
618         $submission = $assign->get_user_submission($student1->id, true);
619         $data = new stdClass();
620         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
621                                          'text'=>'Submission text',
622                                          'format'=>FORMAT_MOODLE);
623         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
624         $plugin->save($submission, $data);
626         // Ready to test.
627         $this->setUser($teacher);
628         $students = array($student1->id, $student2->id);
629         $result = mod_assign_external::lock_submissions($instance->id, $students);
630         $result = external_api::clean_returnvalue(mod_assign_external::lock_submissions_returns(), $result);
632         // Check for 0 warnings.
633         $this->assertEquals(0, count($result));
635         $result = mod_assign_external::unlock_submissions($instance->id, $students);
636         $result = external_api::clean_returnvalue(mod_assign_external::unlock_submissions_returns(), $result);
638         // Check for 0 warnings.
639         $this->assertEquals(0, count($result));
641         $this->setUser($student2);
642         $submission = $assign->get_user_submission($student2->id, true);
643         $data = new stdClass();
644         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
645                                          'text'=>'Submission text',
646                                          'format'=>FORMAT_MOODLE);
647         $notices = array();
648         $assign->save_submission($data, $notices);
649     }
651     /**
652      * Test submit_for_grading
653      */
654     public function test_submit_for_grading() {
655         global $DB, $USER;
657         $this->resetAfterTest(true);
658         // Create a course and assignment and users.
659         $course = self::getDataGenerator()->create_course();
661         set_config('submissionreceipts', 0, 'assign');
662         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
663         $params['course'] = $course->id;
664         $params['assignsubmission_onlinetext_enabled'] = 1;
665         $params['submissiondrafts'] = 1;
666         $params['sendnotifications'] = 0;
667         $params['requiresubmissionstatement'] = 1;
668         $instance = $generator->create_instance($params);
669         $cm = get_coursemodule_from_instance('assign', $instance->id);
670         $context = context_module::instance($cm->id);
672         $assign = new assign($context, $cm, $course);
674         $student1 = self::getDataGenerator()->create_user();
675         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
676         $this->getDataGenerator()->enrol_user($student1->id,
677                                               $course->id,
678                                               $studentrole->id);
680         // Create a student1 with an online text submission.
681         // Simulate a submission.
682         $this->setUser($student1);
683         $submission = $assign->get_user_submission($student1->id, true);
684         $data = new stdClass();
685         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
686                                          'text'=>'Submission text',
687                                          'format'=>FORMAT_MOODLE);
688         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
689         $plugin->save($submission, $data);
691         $result = mod_assign_external::submit_for_grading($instance->id, false);
692         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
694         // Should be 1 fail because the submission statement was not aceptted.
695         $this->assertEquals(1, count($result));
697         $result = mod_assign_external::submit_for_grading($instance->id, true);
698         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
700         // Check for 0 warnings.
701         $this->assertEquals(0, count($result));
703         $submission = $assign->get_user_submission($student1->id, false);
705         $this->assertEquals(ASSIGN_SUBMISSION_STATUS_SUBMITTED, $submission->status);
706     }
708     /**
709      * Test save_user_extensions
710      */
711     public function test_save_user_extensions() {
712         global $DB, $USER;
714         $this->resetAfterTest(true);
715         // Create a course and assignment and users.
716         $course = self::getDataGenerator()->create_course();
718         $teacher = self::getDataGenerator()->create_user();
719         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
720         $this->getDataGenerator()->enrol_user($teacher->id,
721                                               $course->id,
722                                               $teacherrole->id);
723         $this->setUser($teacher);
725         $now = time();
726         $yesterday = $now - 24*60*60;
727         $tomorrow = $now + 24*60*60;
728         set_config('submissionreceipts', 0, 'assign');
729         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
730         $params['course'] = $course->id;
731         $params['submissiondrafts'] = 1;
732         $params['sendnotifications'] = 0;
733         $params['duedate'] = $yesterday;
734         $params['cutoffdate'] = $now - 10;
735         $instance = $generator->create_instance($params);
736         $cm = get_coursemodule_from_instance('assign', $instance->id);
737         $context = context_module::instance($cm->id);
739         $assign = new assign($context, $cm, $course);
741         $student1 = self::getDataGenerator()->create_user();
742         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
743         $this->getDataGenerator()->enrol_user($student1->id,
744                                               $course->id,
745                                               $studentrole->id);
747         $this->setUser($student1);
748         $result = mod_assign_external::submit_for_grading($instance->id, true);
749         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
751         // Check for 0 warnings.
752         $this->assertEquals(1, count($result));
754         $this->setUser($teacher);
755         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
756         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
757         $this->assertEquals(1, count($result));
759         $this->setUser($teacher);
760         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($yesterday - 10));
761         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
762         $this->assertEquals(1, count($result));
764         $this->setUser($teacher);
765         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($tomorrow));
766         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
767         $this->assertEquals(0, count($result));
769         $this->setUser($student1);
770         $result = mod_assign_external::submit_for_grading($instance->id, true);
771         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
772         $this->assertEquals(0, count($result));
774         $this->setUser($student1);
775         $result = mod_assign_external::save_user_extensions($instance->id, array($student1->id), array($now, $tomorrow));
776         $result = external_api::clean_returnvalue(mod_assign_external::save_user_extensions_returns(), $result);
778     }
780     /**
781      * Test reveal_identities
782      */
783     public function test_reveal_identities() {
784         global $DB, $USER;
786         $this->resetAfterTest(true);
787         // Create a course and assignment and users.
788         $course = self::getDataGenerator()->create_course();
790         $teacher = self::getDataGenerator()->create_user();
791         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
792         $this->getDataGenerator()->enrol_user($teacher->id,
793                                               $course->id,
794                                               $teacherrole->id);
795         $this->setUser($teacher);
797         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
798         $params['course'] = $course->id;
799         $params['submissiondrafts'] = 1;
800         $params['sendnotifications'] = 0;
801         $params['blindmarking'] = 1;
802         $instance = $generator->create_instance($params);
803         $cm = get_coursemodule_from_instance('assign', $instance->id);
804         $context = context_module::instance($cm->id);
806         $assign = new assign($context, $cm, $course);
808         $student1 = self::getDataGenerator()->create_user();
809         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
810         $this->getDataGenerator()->enrol_user($student1->id,
811                                               $course->id,
812                                               $studentrole->id);
814         $this->setUser($student1);
815         $this->setExpectedException('required_capability_exception');
816         $result = mod_assign_external::reveal_identities($instance->id);
817         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
818         $this->assertEquals(1, count($result));
819         $this->assertEquals(true, $assign->is_blind_marking());
821         $this->setUser($teacher);
822         $result = mod_assign_external::reveal_identities($instance->id);
823         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
824         $this->assertEquals(0, count($result));
825         $this->assertEquals(false, $assign->is_blind_marking());
827         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
828         $params['course'] = $course->id;
829         $params['submissiondrafts'] = 1;
830         $params['sendnotifications'] = 0;
831         $params['blindmarking'] = 0;
832         $instance = $generator->create_instance($params);
833         $cm = get_coursemodule_from_instance('assign', $instance->id);
834         $context = context_module::instance($cm->id);
836         $assign = new assign($context, $cm, $course);
837         $result = mod_assign_external::reveal_identities($instance->id);
838         $result = external_api::clean_returnvalue(mod_assign_external::reveal_identities_returns(), $result);
839         $this->assertEquals(1, count($result));
840         $this->assertEquals(false, $assign->is_blind_marking());
842     }
844     /**
845      * Test revert_submissions_to_draft
846      */
847     public function test_revert_submissions_to_draft() {
848         global $DB, $USER;
850         $this->resetAfterTest(true);
851         set_config('submissionreceipts', 0, 'assign');
852         // Create a course and assignment and users.
853         $course = self::getDataGenerator()->create_course();
855         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
856         $params['course'] = $course->id;
857         $params['sendnotifications'] = 0;
858         $params['submissiondrafts'] = 1;
859         $instance = $generator->create_instance($params);
860         $cm = get_coursemodule_from_instance('assign', $instance->id);
861         $context = context_module::instance($cm->id);
863         $assign = new assign($context, $cm, $course);
865         $student1 = self::getDataGenerator()->create_user();
866         $student2 = self::getDataGenerator()->create_user();
867         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
868         $this->getDataGenerator()->enrol_user($student1->id,
869                                               $course->id,
870                                               $studentrole->id);
871         $this->getDataGenerator()->enrol_user($student2->id,
872                                               $course->id,
873                                               $studentrole->id);
874         $teacher = self::getDataGenerator()->create_user();
875         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
876         $this->getDataGenerator()->enrol_user($teacher->id,
877                                               $course->id,
878                                               $teacherrole->id);
880         // Create a student1 with an online text submission.
881         // Simulate a submission.
882         $this->setUser($student1);
883         $result = mod_assign_external::submit_for_grading($instance->id, true);
884         $result = external_api::clean_returnvalue(mod_assign_external::submit_for_grading_returns(), $result);
885         $this->assertEquals(0, count($result));
887         // Ready to test.
888         $this->setUser($teacher);
889         $students = array($student1->id, $student2->id);
890         $result = mod_assign_external::revert_submissions_to_draft($instance->id, array($student1->id));
891         $result = external_api::clean_returnvalue(mod_assign_external::revert_submissions_to_draft_returns(), $result);
893         // Check for 0 warnings.
894         $this->assertEquals(0, count($result));
896     }
898     /**
899      * Test save_submission
900      */
901     public function test_save_submission() {
902         global $DB, $USER;
904         $this->resetAfterTest(true);
905         // Create a course and assignment and users.
906         $course = self::getDataGenerator()->create_course();
908         $teacher = self::getDataGenerator()->create_user();
909         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
910         $this->getDataGenerator()->enrol_user($teacher->id,
911                                               $course->id,
912                                               $teacherrole->id);
913         $this->setUser($teacher);
915         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
916         $params['course'] = $course->id;
917         $params['assignsubmission_onlinetext_enabled'] = 1;
918         $params['assignsubmission_file_enabled'] = 1;
919         $params['assignsubmission_file_maxfiles'] = 5;
920         $params['assignsubmission_file_maxsizebytes'] = 1024*1024;
921         $instance = $generator->create_instance($params);
922         $cm = get_coursemodule_from_instance('assign', $instance->id);
923         $context = context_module::instance($cm->id);
925         $assign = new assign($context, $cm, $course);
927         $student1 = self::getDataGenerator()->create_user();
928         $student2 = self::getDataGenerator()->create_user();
929         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
930         $this->getDataGenerator()->enrol_user($student1->id,
931                                               $course->id,
932                                               $studentrole->id);
933         $this->getDataGenerator()->enrol_user($student2->id,
934                                               $course->id,
935                                               $studentrole->id);
936         // Create a student1 with an online text submission.
937         // Simulate a submission.
938         $this->setUser($student1);
940         // Create a file in a draft area.
941         $draftidfile = file_get_unused_draft_itemid();
943         $usercontext = context_user::instance($student1->id);
944         $filerecord = array(
945             'contextid' => $usercontext->id,
946             'component' => 'user',
947             'filearea'  => 'draft',
948             'itemid'    => $draftidfile,
949             'filepath'  => '/',
950             'filename'  => 'testtext.txt',
951         );
953         $fs = get_file_storage();
954         $fs->create_file_from_string($filerecord, 'text contents');
956         // Create another file in a different draft area.
957         $draftidonlinetext = file_get_unused_draft_itemid();
959         $filerecord = array(
960             'contextid' => $usercontext->id,
961             'component' => 'user',
962             'filearea'  => 'draft',
963             'itemid'    => $draftidonlinetext,
964             'filepath'  => '/',
965             'filename'  => 'shouldbeanimage.txt',
966         );
968         $fs->create_file_from_string($filerecord, 'image contents (not really)');
970         // Now try a submission.
971         $submissionpluginparams = array();
972         $submissionpluginparams['files_filemanager'] = $draftidfile;
973         $onlinetexteditorparams = array('text'=>'Yeeha!',
974                                         'format'=>1,
975                                         'itemid'=>$draftidonlinetext);
976         $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
977         $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
978         $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
980         $this->assertEquals(0, count($result));
982         // Set up a due and cutoff passed date.
983         $instance->duedate = time() - WEEKSECS;
984         $instance->cutoffdate = time() - WEEKSECS;
985         $DB->update_record('assign', $instance);
987         $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
988         $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
990         $this->assertCount(1, $result);
991         $this->assertEquals(get_string('duedatereached', 'assign'), $result[0]['item']);
992     }
994     /**
995      * Test save_grade
996      */
997     public function test_save_grade() {
998         global $DB, $USER;
1000         $this->resetAfterTest(true);
1001         // Create a course and assignment and users.
1002         $course = self::getDataGenerator()->create_course();
1004         $teacher = self::getDataGenerator()->create_user();
1005         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
1006         $this->getDataGenerator()->enrol_user($teacher->id,
1007                                               $course->id,
1008                                               $teacherrole->id);
1009         $this->setUser($teacher);
1011         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1012         $params['course'] = $course->id;
1013         $params['assignfeedback_file_enabled'] = 1;
1014         $params['assignfeedback_comments_enabled'] = 1;
1015         $instance = $generator->create_instance($params);
1016         $cm = get_coursemodule_from_instance('assign', $instance->id);
1017         $context = context_module::instance($cm->id);
1019         $assign = new assign($context, $cm, $course);
1021         $student1 = self::getDataGenerator()->create_user();
1022         $student2 = self::getDataGenerator()->create_user();
1023         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1024         $this->getDataGenerator()->enrol_user($student1->id,
1025                                               $course->id,
1026                                               $studentrole->id);
1027         $this->getDataGenerator()->enrol_user($student2->id,
1028                                               $course->id,
1029                                               $studentrole->id);
1030         // Simulate a grade.
1031         $this->setUser($teacher);
1033         // Create a file in a draft area.
1034         $draftidfile = file_get_unused_draft_itemid();
1036         $usercontext = context_user::instance($teacher->id);
1037         $filerecord = array(
1038             'contextid' => $usercontext->id,
1039             'component' => 'user',
1040             'filearea'  => 'draft',
1041             'itemid'    => $draftidfile,
1042             'filepath'  => '/',
1043             'filename'  => 'testtext.txt',
1044         );
1046         $fs = get_file_storage();
1047         $fs->create_file_from_string($filerecord, 'text contents');
1049         // Now try a grade.
1050         $feedbackpluginparams = array();
1051         $feedbackpluginparams['files_filemanager'] = $draftidfile;
1052         $feedbackeditorparams = array('text' => 'Yeeha!',
1053                                         'format' => 1);
1054         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1055         $result = mod_assign_external::save_grade($instance->id,
1056                                                   $student1->id,
1057                                                   50.0,
1058                                                   -1,
1059                                                   true,
1060                                                   'released',
1061                                                   false,
1062                                                   $feedbackpluginparams);
1063         // No warnings.
1064         $this->assertNull($result);
1066         $result = mod_assign_external::get_grades(array($instance->id));
1067         $result = external_api::clean_returnvalue(mod_assign_external::get_grades_returns(), $result);
1069         $this->assertEquals($result['assignments'][0]['grades'][0]['grade'], '50.0');
1070     }
1072     /**
1073      * Test save grades with advanced grading data
1074      */
1075     public function test_save_grades_with_advanced_grading() {
1076         global $DB, $USER;
1078         $this->resetAfterTest(true);
1079         // Create a course and assignment and users.
1080         $course = self::getDataGenerator()->create_course();
1082         $teacher = self::getDataGenerator()->create_user();
1083         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1084         $this->getDataGenerator()->enrol_user($teacher->id,
1085                                               $course->id,
1086                                               $teacherrole->id);
1088         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1089         $params['course'] = $course->id;
1090         $params['assignfeedback_file_enabled'] = 0;
1091         $params['assignfeedback_comments_enabled'] = 0;
1092         $instance = $generator->create_instance($params);
1093         $cm = get_coursemodule_from_instance('assign', $instance->id);
1094         $context = context_module::instance($cm->id);
1096         $assign = new assign($context, $cm, $course);
1098         $student1 = self::getDataGenerator()->create_user();
1099         $student2 = self::getDataGenerator()->create_user();
1100         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1101         $this->getDataGenerator()->enrol_user($student1->id,
1102                                               $course->id,
1103                                               $studentrole->id);
1104         $this->getDataGenerator()->enrol_user($student2->id,
1105                                               $course->id,
1106                                               $studentrole->id);
1108         $this->setUser($teacher);
1110         $feedbackpluginparams = array();
1111         $feedbackpluginparams['files_filemanager'] = 0;
1112         $feedbackeditorparams = array('text' => '', 'format' => 1);
1113         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1115         // Create advanced grading data.
1116         // Create grading area.
1117         $gradingarea = array(
1118             'contextid' => $context->id,
1119             'component' => 'mod_assign',
1120             'areaname' => 'submissions',
1121             'activemethod' => 'rubric'
1122         );
1123         $areaid = $DB->insert_record('grading_areas', $gradingarea);
1125         // Create a rubric grading definition.
1126         $rubricdefinition = array (
1127             'areaid' => $areaid,
1128             'method' => 'rubric',
1129             'name' => 'test',
1130             'status' => 20,
1131             'copiedfromid' => 1,
1132             'timecreated' => 1,
1133             'usercreated' => $teacher->id,
1134             'timemodified' => 1,
1135             'usermodified' => $teacher->id,
1136             'timecopied' => 0
1137         );
1138         $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
1140         // Create a criterion with a level.
1141         $rubriccriteria = array (
1142              'definitionid' => $definitionid,
1143              'sortorder' => 1,
1144              'description' => 'Demonstrate an understanding of disease control',
1145              'descriptionformat' => 0
1146         );
1147         $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria);
1148         $rubriclevel1 = array (
1149             'criterionid' => $criterionid,
1150             'score' => 50,
1151             'definition' => 'pass',
1152             'definitionformat' => 0
1153         );
1154         $rubriclevel2 = array (
1155             'criterionid' => $criterionid,
1156             'score' => 100,
1157             'definition' => 'excellent',
1158             'definitionformat' => 0
1159         );
1160         $rubriclevel3 = array (
1161             'criterionid' => $criterionid,
1162             'score' => 0,
1163             'definition' => 'fail',
1164             'definitionformat' => 0
1165         );
1166         $levelid1 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
1167         $levelid2 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
1168         $levelid3 = $DB->insert_record('gradingform_rubric_levels', $rubriclevel3);
1170         // Create the filling.
1171         $student1filling = array (
1172             'criterionid' => $criterionid,
1173             'levelid' => $levelid1,
1174             'remark' => 'well done you passed',
1175             'remarkformat' => 0
1176         );
1178         $student2filling = array (
1179             'criterionid' => $criterionid,
1180             'levelid' => $levelid2,
1181             'remark' => 'Excellent work',
1182             'remarkformat' => 0
1183         );
1185         $student1criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student1filling)));
1186         $student1advancedgradingdata = array('rubric' => array('criteria' => $student1criteria));
1188         $student2criteria = array(array('criterionid' => $criterionid, 'fillings' => array($student2filling)));
1189         $student2advancedgradingdata = array('rubric' => array('criteria' => $student2criteria));
1191         $grades = array();
1192         $student1gradeinfo = array();
1193         $student1gradeinfo['userid'] = $student1->id;
1194         $student1gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1195         $student1gradeinfo['attemptnumber'] = -1;
1196         $student1gradeinfo['addattempt'] = true;
1197         $student1gradeinfo['workflowstate'] = 'released';
1198         $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1199         $student1gradeinfo['advancedgradingdata'] = $student1advancedgradingdata;
1200         $grades[] = $student1gradeinfo;
1202         $student2gradeinfo = array();
1203         $student2gradeinfo['userid'] = $student2->id;
1204         $student2gradeinfo['grade'] = 0; // Ignored since advanced grading is being used.
1205         $student2gradeinfo['attemptnumber'] = -1;
1206         $student2gradeinfo['addattempt'] = true;
1207         $student2gradeinfo['workflowstate'] = 'released';
1208         $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1209         $student2gradeinfo['advancedgradingdata'] = $student2advancedgradingdata;
1210         $grades[] = $student2gradeinfo;
1212         $result = mod_assign_external::save_grades($instance->id, false, $grades);
1213         $this->assertNull($result);
1215         $student1grade = $DB->get_record('assign_grades',
1216                                          array('userid' => $student1->id, 'assignment' => $instance->id),
1217                                          '*',
1218                                          MUST_EXIST);
1219         $this->assertEquals($student1grade->grade, '50.0');
1221         $student2grade = $DB->get_record('assign_grades',
1222                                          array('userid' => $student2->id, 'assignment' => $instance->id),
1223                                          '*',
1224                                          MUST_EXIST);
1225         $this->assertEquals($student2grade->grade, '100.0');
1226     }
1228     /**
1229      * Test save grades for a team submission
1230      */
1231     public function test_save_grades_with_group_submission() {
1232         global $DB, $USER, $CFG;
1233         require_once($CFG->dirroot . '/group/lib.php');
1235         $this->resetAfterTest(true);
1236         // Create a course and assignment and users.
1237         $course = self::getDataGenerator()->create_course();
1239         $teacher = self::getDataGenerator()->create_user();
1240         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1241         $this->getDataGenerator()->enrol_user($teacher->id,
1242                                               $course->id,
1243                                               $teacherrole->id);
1245         $groupingdata = array();
1246         $groupingdata['courseid'] = $course->id;
1247         $groupingdata['name'] = 'Group assignment grouping';
1249         $grouping = self::getDataGenerator()->create_grouping($groupingdata);
1251         $group1data = array();
1252         $group1data['courseid'] = $course->id;
1253         $group1data['name'] = 'Team 1';
1254         $group2data = array();
1255         $group2data['courseid'] = $course->id;
1256         $group2data['name'] = 'Team 2';
1258         $group1 = self::getDataGenerator()->create_group($group1data);
1259         $group2 = self::getDataGenerator()->create_group($group2data);
1261         groups_assign_grouping($grouping->id, $group1->id);
1262         groups_assign_grouping($grouping->id, $group2->id);
1264         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1265         $params['course'] = $course->id;
1266         $params['teamsubmission'] = 1;
1267         $params['teamsubmissiongroupingid'] = $grouping->id;
1268         $instance = $generator->create_instance($params);
1269         $cm = get_coursemodule_from_instance('assign', $instance->id);
1270         $context = context_module::instance($cm->id);
1272         $assign = new assign($context, $cm, $course);
1274         $student1 = self::getDataGenerator()->create_user();
1275         $student2 = self::getDataGenerator()->create_user();
1276         $student3 = self::getDataGenerator()->create_user();
1277         $student4 = self::getDataGenerator()->create_user();
1278         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1279         $this->getDataGenerator()->enrol_user($student1->id,
1280                                               $course->id,
1281                                               $studentrole->id);
1282         $this->getDataGenerator()->enrol_user($student2->id,
1283                                               $course->id,
1284                                               $studentrole->id);
1285         $this->getDataGenerator()->enrol_user($student3->id,
1286                                               $course->id,
1287                                               $studentrole->id);
1288         $this->getDataGenerator()->enrol_user($student4->id,
1289                                               $course->id,
1290                                               $studentrole->id);
1292         groups_add_member($group1->id, $student1->id);
1293         groups_add_member($group1->id, $student2->id);
1294         groups_add_member($group1->id, $student3->id);
1295         groups_add_member($group2->id, $student4->id);
1296         $this->setUser($teacher);
1298         $feedbackpluginparams = array();
1299         $feedbackpluginparams['files_filemanager'] = 0;
1300         $feedbackeditorparams = array('text' => '', 'format' => 1);
1301         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1303         $grades1 = array();
1304         $student1gradeinfo = array();
1305         $student1gradeinfo['userid'] = $student1->id;
1306         $student1gradeinfo['grade'] = 50;
1307         $student1gradeinfo['attemptnumber'] = -1;
1308         $student1gradeinfo['addattempt'] = true;
1309         $student1gradeinfo['workflowstate'] = 'released';
1310         $student1gradeinfo['plugindata'] = $feedbackpluginparams;
1311         $grades1[] = $student1gradeinfo;
1313         $student2gradeinfo = array();
1314         $student2gradeinfo['userid'] = $student2->id;
1315         $student2gradeinfo['grade'] = 75;
1316         $student2gradeinfo['attemptnumber'] = -1;
1317         $student2gradeinfo['addattempt'] = true;
1318         $student2gradeinfo['workflowstate'] = 'released';
1319         $student2gradeinfo['plugindata'] = $feedbackpluginparams;
1320         $grades1[] = $student2gradeinfo;
1322         $this->setExpectedException('invalid_parameter_exception');
1323         // Expect an exception since 2 grades have been submitted for the same team.
1324         $result = mod_assign_external::save_grades($instance->id, true, $grades1);
1325         $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
1327         $grades2 = array();
1328         $student3gradeinfo = array();
1329         $student3gradeinfo['userid'] = $student3->id;
1330         $student3gradeinfo['grade'] = 50;
1331         $student3gradeinfo['attemptnumber'] = -1;
1332         $student3gradeinfo['addattempt'] = true;
1333         $student3gradeinfo['workflowstate'] = 'released';
1334         $student3gradeinfo['plugindata'] = $feedbackpluginparams;
1335         $grades2[] = $student3gradeinfo;
1337         $student4gradeinfo = array();
1338         $student4gradeinfo['userid'] = $student4->id;
1339         $student4gradeinfo['grade'] = 75;
1340         $student4gradeinfo['attemptnumber'] = -1;
1341         $student4gradeinfo['addattempt'] = true;
1342         $student4gradeinfo['workflowstate'] = 'released';
1343         $student4gradeinfo['plugindata'] = $feedbackpluginparams;
1344         $grades2[] = $student4gradeinfo;
1345         $result = mod_assign_external::save_grades($instance->id, true, $grades2);
1346         $result = external_api::clean_returnvalue(mod_assign_external::save_grades_returns(), $result);
1347         // There should be no warnings.
1348         $this->assertEquals(0, count($result));
1350         $student3grade = $DB->get_record('assign_grades',
1351                                          array('userid' => $student3->id, 'assignment' => $instance->id),
1352                                          '*',
1353                                          MUST_EXIST);
1354         $this->assertEquals($student3grade->grade, '50.0');
1356         $student4grade = $DB->get_record('assign_grades',
1357                                          array('userid' => $student4->id, 'assignment' => $instance->id),
1358                                          '*',
1359                                          MUST_EXIST);
1360         $this->assertEquals($student4grade->grade, '75.0');
1361     }
1363     /**
1364      * Test copy_previous_attempt
1365      */
1366     public function test_copy_previous_attempt() {
1367         global $DB, $USER;
1369         $this->resetAfterTest(true);
1370         // Create a course and assignment and users.
1371         $course = self::getDataGenerator()->create_course();
1373         $teacher = self::getDataGenerator()->create_user();
1374         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
1375         $this->getDataGenerator()->enrol_user($teacher->id,
1376                                               $course->id,
1377                                               $teacherrole->id);
1378         $this->setUser($teacher);
1380         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1381         $params['course'] = $course->id;
1382         $params['assignsubmission_onlinetext_enabled'] = 1;
1383         $params['assignsubmission_file_enabled'] = 0;
1384         $params['assignfeedback_file_enabled'] = 0;
1385         $params['attemptreopenmethod'] = 'manual';
1386         $params['maxattempts'] = 5;
1387         $instance = $generator->create_instance($params);
1388         $cm = get_coursemodule_from_instance('assign', $instance->id);
1389         $context = context_module::instance($cm->id);
1391         $assign = new assign($context, $cm, $course);
1393         $student1 = self::getDataGenerator()->create_user();
1394         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
1395         $this->getDataGenerator()->enrol_user($student1->id,
1396                                               $course->id,
1397                                               $studentrole->id);
1398         // Now try a submission.
1399         $this->setUser($student1);
1400         $draftidonlinetext = file_get_unused_draft_itemid();
1401         $submissionpluginparams = array();
1402         $onlinetexteditorparams = array('text'=>'Yeeha!',
1403                                         'format'=>1,
1404                                         'itemid'=>$draftidonlinetext);
1405         $submissionpluginparams['onlinetext_editor'] = $onlinetexteditorparams;
1406         $submissionpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1407         $result = mod_assign_external::save_submission($instance->id, $submissionpluginparams);
1408         $result = external_api::clean_returnvalue(mod_assign_external::save_submission_returns(), $result);
1410         $this->setUser($teacher);
1411         // Add a grade and reopen the attempt.
1412         // Now try a grade.
1413         $feedbackpluginparams = array();
1414         $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1415         $feedbackeditorparams = array('text'=>'Yeeha!',
1416                                         'format'=>1);
1417         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1418         $result = mod_assign_external::save_grade($instance->id,
1419                                                   $student1->id,
1420                                                   50.0,
1421                                                   -1,
1422                                                   true,
1423                                                   'released',
1424                                                   false,
1425                                                   $feedbackpluginparams);
1426         $this->assertNull($result);
1428         $this->setUser($student1);
1429         // Now copy the previous attempt.
1430         $result = mod_assign_external::copy_previous_attempt($instance->id);
1431         $result = external_api::clean_returnvalue(mod_assign_external::copy_previous_attempt_returns(), $result);
1432         // No warnings.
1433         $this->assertEquals(0, count($result));
1435         $this->setUser($teacher);
1436         $result = mod_assign_external::get_submissions(array($instance->id));
1437         $result = external_api::clean_returnvalue(mod_assign_external::get_submissions_returns(), $result);
1439         // Check we are now on the second attempt.
1440         $this->assertEquals($result['assignments'][0]['submissions'][0]['attemptnumber'], 1);
1441         // Check the plugins data is not empty.
1442         $this->assertNotEmpty($result['assignments'][0]['submissions'][0]['plugins']);
1444     }
1446     /**
1447      * Test set_user_flags
1448      */
1449     public function test_set_user_flags() {
1450         global $DB, $USER;
1452         $this->resetAfterTest(true);
1453         // Create a course and assignment.
1454         $coursedata['idnumber'] = 'idnumbercourse';
1455         $coursedata['fullname'] = 'Lightwork Course';
1456         $coursedata['summary'] = 'Lightwork Course description';
1457         $coursedata['summaryformat'] = FORMAT_MOODLE;
1458         $course = self::getDataGenerator()->create_course($coursedata);
1460         $assigndata['course'] = $course->id;
1461         $assigndata['name'] = 'lightwork assignment';
1463         $assign = self::getDataGenerator()->create_module('assign', $assigndata);
1465         // Create a manual enrolment record.
1466         $manualenroldata['enrol'] = 'manual';
1467         $manualenroldata['status'] = 0;
1468         $manualenroldata['courseid'] = $course->id;
1469         $enrolid = $DB->insert_record('enrol', $manualenroldata);
1471         // Create a teacher and give them capabilities.
1472         $context = context_course::instance($course->id);
1473         $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $context->id, 3);
1474         $context = context_module::instance($assign->cmid);
1475         $this->assignUserCapability('mod/assign:grade', $context->id, $roleid);
1477         // Create the teacher's enrolment record.
1478         $userenrolmentdata['status'] = 0;
1479         $userenrolmentdata['enrolid'] = $enrolid;
1480         $userenrolmentdata['userid'] = $USER->id;
1481         $DB->insert_record('user_enrolments', $userenrolmentdata);
1483         // Create a student.
1484         $student = self::getDataGenerator()->create_user();
1486         // Create test user flags record.
1487         $userflags = array();
1488         $userflag['userid'] = $student->id;
1489         $userflag['workflowstate'] = 'inmarking';
1490         $userflag['allocatedmarker'] = $USER->id;
1491         $userflags = array($userflag);
1493         $createduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1494         // We need to execute the return values cleaning process to simulate the web service server.
1495         $createduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $createduserflags);
1497         $this->assertEquals($student->id, $createduserflags[0]['userid']);
1498         $createduserflag = $DB->get_record('assign_user_flags', array('id' => $createduserflags[0]['id']));
1500         // Confirm that all data was inserted correctly.
1501         $this->assertEquals($student->id,  $createduserflag->userid);
1502         $this->assertEquals($assign->id, $createduserflag->assignment);
1503         $this->assertEquals(0, $createduserflag->locked);
1504         $this->assertEquals(2, $createduserflag->mailed);
1505         $this->assertEquals(0, $createduserflag->extensionduedate);
1506         $this->assertEquals('inmarking', $createduserflag->workflowstate);
1507         $this->assertEquals($USER->id, $createduserflag->allocatedmarker);
1509         // Create update data.
1510         $userflags = array();
1511         $userflag['userid'] = $createduserflag->userid;
1512         $userflag['workflowstate'] = 'readyforreview';
1513         $userflags = array($userflag);
1515         $updateduserflags = mod_assign_external::set_user_flags($assign->id, $userflags);
1516         // We need to execute the return values cleaning process to simulate the web service server.
1517         $updateduserflags = external_api::clean_returnvalue(mod_assign_external::set_user_flags_returns(), $updateduserflags);
1519         $this->assertEquals($student->id, $updateduserflags[0]['userid']);
1520         $updateduserflag = $DB->get_record('assign_user_flags', array('id' => $updateduserflags[0]['id']));
1522         // Confirm that all data was updated correctly.
1523         $this->assertEquals($student->id,  $updateduserflag->userid);
1524         $this->assertEquals($assign->id, $updateduserflag->assignment);
1525         $this->assertEquals(0, $updateduserflag->locked);
1526         $this->assertEquals(2, $updateduserflag->mailed);
1527         $this->assertEquals(0, $updateduserflag->extensionduedate);
1528         $this->assertEquals('readyforreview', $updateduserflag->workflowstate);
1529         $this->assertEquals($USER->id, $updateduserflag->allocatedmarker);
1530     }
1532     /**
1533      * Test view_grading_table
1534      */
1535     public function test_view_grading_table_invalid_instance() {
1536         global $DB;
1538         $this->resetAfterTest(true);
1540         // Setup test data.
1541         $course = $this->getDataGenerator()->create_course();
1542         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1543         $context = context_module::instance($assign->cmid);
1544         $cm = get_coursemodule_from_instance('assign', $assign->id);
1546         // Test invalid instance id.
1547         $this->setExpectedExceptionRegexp('dml_missing_record_exception');
1548         mod_assign_external::view_grading_table(0);
1549     }
1551     /**
1552      * Test view_grading_table
1553      */
1554     public function test_view_grading_table_not_enrolled() {
1555         global $DB;
1557         $this->resetAfterTest(true);
1559         // Setup test data.
1560         $course = $this->getDataGenerator()->create_course();
1561         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1562         $context = context_module::instance($assign->cmid);
1563         $cm = get_coursemodule_from_instance('assign', $assign->id);
1565         // Test not-enrolled user.
1566         $user = self::getDataGenerator()->create_user();
1567         $this->setUser($user);
1569         $this->setExpectedException('require_login_exception');
1570         mod_assign_external::view_grading_table($assign->id);
1571     }
1573     /**
1574      * Test view_grading_table
1575      */
1576     public function test_view_grading_table_correct() {
1577         global $DB;
1579         $this->resetAfterTest(true);
1581         // Setup test data.
1582         $course = $this->getDataGenerator()->create_course();
1583         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1584         $context = context_module::instance($assign->cmid);
1585         $cm = get_coursemodule_from_instance('assign', $assign->id);
1587         // Test user with full capabilities.
1588         $user = self::getDataGenerator()->create_user();
1589         $this->setUser($user);
1590         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1591         $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
1593         // Trigger and capture the event.
1594         $sink = $this->redirectEvents();
1596         $result = mod_assign_external::view_grading_table($assign->id);
1597         $result = external_api::clean_returnvalue(mod_assign_external::view_grading_table_returns(), $result);
1599         $events = $sink->get_events();
1600         $this->assertCount(1, $events);
1601         $event = array_shift($events);
1603         // Checking that the event contains the expected values.
1604         $this->assertInstanceOf('\mod_assign\event\grading_table_viewed', $event);
1605         $this->assertEquals($context, $event->get_context());
1606         $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id));
1607         $this->assertEquals($moodleurl, $event->get_url());
1608         $this->assertEventContextNotUsed($event);
1609         $this->assertNotEmpty($event->get_name());
1610     }
1612     /**
1613      * Test view_grading_table
1614      */
1615     public function test_view_grading_table_without_capability() {
1616         global $DB;
1618         $this->resetAfterTest(true);
1620         // Setup test data.
1621         $course = $this->getDataGenerator()->create_course();
1622         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1623         $context = context_module::instance($assign->cmid);
1624         $cm = get_coursemodule_from_instance('assign', $assign->id);
1626         // Test user with no capabilities.
1627         $user = self::getDataGenerator()->create_user();
1628         $this->setUser($user);
1629         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1630         $this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
1632         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
1633         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1634         assign_capability('mod/assign:view', CAP_PROHIBIT, $teacherrole->id, $context->id);
1635         // Empty all the caches that may be affected by this change.
1636         accesslib_clear_all_caches_for_unit_testing();
1637         course_modinfo::clear_instance_cache();
1639         $this->setExpectedException('require_login_exception', 'Course or activity not accessible. (Activity is hidden)');
1640         mod_assign_external::view_grading_table($assign->id);
1641     }
1643     /**
1644      * Test subplugins availability
1645      */
1646     public function test_subplugins_availability() {
1647         global $CFG;
1649         require_once($CFG->dirroot . '/mod/assign/adminlib.php');
1650         $this->resetAfterTest(true);
1652         // Hide assignment file submissiong plugin.
1653         $pluginmanager = new assign_plugin_manager('assignsubmission');
1654         $pluginmanager->hide_plugin('file');
1655         $parameters = mod_assign_external::save_submission_parameters();
1657         $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager']));
1659         // Show it again and check that the value is returned as optional.
1660         $pluginmanager->show_plugin('file');
1661         $parameters = mod_assign_external::save_submission_parameters();
1662         $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager']));
1663         $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required);
1665         // Hide feedback file submissiong plugin.
1666         $pluginmanager = new assign_plugin_manager('assignfeedback');
1667         $pluginmanager->hide_plugin('file');
1669         $parameters = mod_assign_external::save_grade_parameters();
1671         $this->assertTrue(!isset($parameters->keys['plugindata']->keys['files_filemanager']));
1673         // Show it again and check that the value is returned as optional.
1674         $pluginmanager->show_plugin('file');
1675         $parameters = mod_assign_external::save_grade_parameters();
1677         $this->assertTrue(isset($parameters->keys['plugindata']->keys['files_filemanager']));
1678         $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['files_filemanager']->required);
1680         // Check a different one.
1681         $pluginmanager->show_plugin('comments');
1682         $this->assertTrue(isset($parameters->keys['plugindata']->keys['assignfeedbackcomments_editor']));
1683         $this->assertEquals(VALUE_OPTIONAL, $parameters->keys['plugindata']->keys['assignfeedbackcomments_editor']->required);
1684     }
1686     /**
1687      * Test test_view_submission_status
1688      */
1689     public function test_view_submission_status() {
1690         global $DB;
1692         $this->resetAfterTest(true);
1694         $this->setAdminUser();
1695         // Setup test data.
1696         $course = $this->getDataGenerator()->create_course();
1697         $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
1698         $context = context_module::instance($assign->cmid);
1699         $cm = get_coursemodule_from_instance('assign', $assign->id);
1701         // Test invalid instance id.
1702         try {
1703             mod_assign_external::view_submission_status(0);
1704             $this->fail('Exception expected due to invalid mod_assign instance id.');
1705         } catch (moodle_exception $e) {
1706             $this->assertEquals('invalidrecord', $e->errorcode);
1707         }
1709         // Test not-enrolled user.
1710         $user = self::getDataGenerator()->create_user();
1711         $this->setUser($user);
1712         try {
1713             mod_assign_external::view_submission_status($assign->id);
1714             $this->fail('Exception expected due to not enrolled user.');
1715         } catch (moodle_exception $e) {
1716             $this->assertEquals('requireloginerror', $e->errorcode);
1717         }
1719         // Test user with full capabilities.
1720         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1721         $this->getDataGenerator()->enrol_user($user->id, $course->id, $studentrole->id);
1723         // Trigger and capture the event.
1724         $sink = $this->redirectEvents();
1726         $result = mod_assign_external::view_submission_status($assign->id);
1727         $result = external_api::clean_returnvalue(mod_assign_external::view_submission_status_returns(), $result);
1729         $events = $sink->get_events();
1730         $this->assertCount(1, $events);
1731         $event = array_shift($events);
1733         // Checking that the event contains the expected values.
1734         $this->assertInstanceOf('\mod_assign\event\submission_status_viewed', $event);
1735         $this->assertEquals($context, $event->get_context());
1736         $moodleurl = new \moodle_url('/mod/assign/view.php', array('id' => $cm->id));
1737         $this->assertEquals($moodleurl, $event->get_url());
1738         $this->assertEventContextNotUsed($event);
1739         $this->assertNotEmpty($event->get_name());
1741         // Test user with no capabilities.
1742         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
1743         assign_capability('mod/assign:view', CAP_PROHIBIT, $studentrole->id, $context->id);
1744         accesslib_clear_all_caches_for_unit_testing();
1745         course_modinfo::clear_instance_cache();
1747         try {
1748             mod_assign_external::view_submission_status($assign->id);
1749             $this->fail('Exception expected due to missing capability.');
1750         } catch (moodle_exception $e) {
1751             $this->assertEquals('requireloginerror', $e->errorcode);
1752         }
1753     }
1755     /**
1756      * Create a submission for testing the get_submission_status function.
1757      * @param  boolean $submitforgrading whether to submit for grading the submission
1758      * @return array an array containing all the required data for testing
1759      */
1760     private function create_submission_for_testing_status($submitforgrading = false) {
1761         global $DB, $CFG;
1762         require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
1764         // Create a course and assignment and users.
1765         $course = self::getDataGenerator()->create_course();
1767         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
1768         $params = array(
1769             'course' => $course->id,
1770             'assignsubmission_file_maxfiles' => 1,
1771             'assignsubmission_file_maxsizebytes' => 1024 * 1024,
1772             'assignsubmission_onlinetext_enabled' => 1,
1773             'assignsubmission_file_enabled' => 1,
1774             'submissiondrafts' => 1,
1775             'assignfeedback_file_enabled' => 1,
1776             'assignfeedback_comments_enabled' => 1,
1777             'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
1778             'sendnotifications' => 0
1779         );
1781         set_config('submissionreceipts', 0, 'assign');
1783         $instance = $generator->create_instance($params);
1784         $cm = get_coursemodule_from_instance('assign', $instance->id);
1785         $context = context_module::instance($cm->id);
1787         $assign = new testable_assign($context, $cm, $course);
1789         $student1 = self::getDataGenerator()->create_user();
1790         $student2 = self::getDataGenerator()->create_user();
1791         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1792         $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
1793         $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
1794         $teacher = self::getDataGenerator()->create_user();
1795         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1796         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
1798         $this->setUser($student1);
1800         // Create a student1 with an online text submission.
1801         // Simulate a submission.
1802         $submission = $assign->get_user_submission($student1->id, true);
1804         $data = new stdClass();
1805         $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1806                                          'text' => 'Submission text',
1807                                          'format' => FORMAT_MOODLE);
1809         $draftidfile = file_get_unused_draft_itemid();
1810         $usercontext = context_user::instance($student1->id);
1811         $filerecord = array(
1812             'contextid' => $usercontext->id,
1813             'component' => 'user',
1814             'filearea'  => 'draft',
1815             'itemid'    => $draftidfile,
1816             'filepath'  => '/',
1817             'filename'  => 't.txt',
1818         );
1819         $fs = get_file_storage();
1820         $fs->create_file_from_string($filerecord, 'text contents');
1822         $data->files_filemanager = $draftidfile;
1824         $notices = array();
1825         $assign->save_submission($data, $notices);
1827         if ($submitforgrading) {
1828             // Now, submit the draft for grading.
1829             $notices = array();
1831             $data = new stdClass;
1832             $data->userid = $student1->id;
1833             $assign->submit_for_grading($data, $notices);
1834         }
1836         return array($assign, $instance, $student1, $student2, $teacher);
1837     }
1839     /**
1840      * Test get_submission_status for a draft submission.
1841      */
1842     public function test_get_submission_status_in_draft_status() {
1843         $this->resetAfterTest(true);
1845         list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status();
1847         $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1848         // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1849         $this->assertDebuggingCalled();
1851         $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1853         // The submission is now in draft mode.
1854         $this->assertCount(0, $result['warnings']);
1855         $this->assertFalse(isset($result['gradingsummary']));
1856         $this->assertFalse(isset($result['feedback']));
1857         $this->assertFalse(isset($result['previousattempts']));
1859         $this->assertTrue($result['lastattempt']['submissionsenabled']);
1860         $this->assertTrue($result['lastattempt']['canedit']);
1861         $this->assertTrue($result['lastattempt']['cansubmit']);
1862         $this->assertFalse($result['lastattempt']['locked']);
1863         $this->assertFalse($result['lastattempt']['graded']);
1864         $this->assertEmpty($result['lastattempt']['extensionduedate']);
1865         $this->assertFalse($result['lastattempt']['blindmarking']);
1866         $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1867         $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1869         $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']);
1870         $this->assertEquals(0, $result['lastattempt']['submission']['attemptnumber']);
1871         $this->assertEquals('draft', $result['lastattempt']['submission']['status']);
1872         $this->assertEquals(0, $result['lastattempt']['submission']['groupid']);
1873         $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']);
1874         $this->assertEquals(1, $result['lastattempt']['submission']['latest']);
1876         // Map plugins based on their type - we can't rely on them being in a
1877         // particular order, especially if 3rd party plugins are installed.
1878         $submissionplugins = array();
1879         foreach ($result['lastattempt']['submission']['plugins'] as $plugin) {
1880             $submissionplugins[$plugin['type']] = $plugin;
1881         }
1882         $this->assertEquals('Submission text', $submissionplugins['onlinetext']['editorfields'][0]['text']);
1883         $this->assertEquals('/t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']);
1884     }
1886     /**
1887      * Test get_submission_status for a submitted submission.
1888      */
1889     public function test_get_submission_status_in_submission_status() {
1890         $this->resetAfterTest(true);
1892         list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1894         $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1895         // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1896         $this->assertDebuggingCalled();
1897         $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1899         $this->assertCount(0, $result['warnings']);
1900         $this->assertFalse(isset($result['gradingsummary']));
1901         $this->assertFalse(isset($result['feedback']));
1902         $this->assertFalse(isset($result['previousattempts']));
1904         $this->assertTrue($result['lastattempt']['submissionsenabled']);
1905         $this->assertFalse($result['lastattempt']['canedit']);
1906         $this->assertFalse($result['lastattempt']['cansubmit']);
1907         $this->assertFalse($result['lastattempt']['locked']);
1908         $this->assertFalse($result['lastattempt']['graded']);
1909         $this->assertEmpty($result['lastattempt']['extensionduedate']);
1910         $this->assertFalse($result['lastattempt']['blindmarking']);
1911         $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1912         $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1914     }
1916     /**
1917      * Test get_submission_status using the teacher role.
1918      */
1919     public function test_get_submission_status_in_submission_status_for_teacher() {
1920         $this->resetAfterTest(true);
1922         list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1924         // Now, as teacher, see the grading summary.
1925         $this->setUser($teacher);
1926         $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1927         // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1928         $this->assertDebuggingCalled();
1929         $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1931         $this->assertCount(0, $result['warnings']);
1932         $this->assertFalse(isset($result['lastattempt']));
1933         $this->assertFalse(isset($result['feedback']));
1934         $this->assertFalse(isset($result['previousattempts']));
1936         $this->assertEquals(2, $result['gradingsummary']['participantcount']);
1937         $this->assertEquals(0, $result['gradingsummary']['submissiondraftscount']);
1938         $this->assertEquals(1, $result['gradingsummary']['submissionsenabled']);
1939         $this->assertEquals(1, $result['gradingsummary']['submissionssubmittedcount']);
1940         $this->assertEquals(1, $result['gradingsummary']['submissionsneedgradingcount']);
1941         $this->assertFalse($result['gradingsummary']['warnofungroupedusers']);
1942     }
1944     /**
1945      * Test get_submission_status for a reopened submission.
1946      */
1947     public function test_get_submission_status_in_reopened_status() {
1948         global $USER;
1950         $this->resetAfterTest(true);
1952         list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status(true);
1954         $this->setUser($teacher);
1955         // Grade and reopen.
1956         $feedbackpluginparams = array();
1957         $feedbackpluginparams['files_filemanager'] = file_get_unused_draft_itemid();
1958         $feedbackeditorparams = array('text' => 'Yeeha!',
1959                                         'format' => 1);
1960         $feedbackpluginparams['assignfeedbackcomments_editor'] = $feedbackeditorparams;
1961         $result = mod_assign_external::save_grade($instance->id,
1962                                                   $student1->id,
1963                                                   50.0,
1964                                                   -1,
1965                                                   false,
1966                                                   'released',
1967                                                   false,
1968                                                   $feedbackpluginparams);
1969         $USER->ignoresesskey = true;
1970         $assign->testable_process_add_attempt($student1->id);
1972         $this->setUser($student1);
1974         $result = mod_assign_external::get_submission_status($assign->get_instance()->id);
1975         // We expect debugging because of the $PAGE object, this won't happen in a normal WS request.
1976         $this->assertDebuggingCalled();
1977         $result = external_api::clean_returnvalue(mod_assign_external::get_submission_status_returns(), $result);
1979         $this->assertCount(0, $result['warnings']);
1980         $this->assertFalse(isset($result['gradingsummary']));
1982         $this->assertTrue($result['lastattempt']['submissionsenabled']);
1983         $this->assertTrue($result['lastattempt']['canedit']);
1984         $this->assertFalse($result['lastattempt']['cansubmit']);
1985         $this->assertFalse($result['lastattempt']['locked']);
1986         $this->assertFalse($result['lastattempt']['graded']);
1987         $this->assertEmpty($result['lastattempt']['extensionduedate']);
1988         $this->assertFalse($result['lastattempt']['blindmarking']);
1989         $this->assertCount(0, $result['lastattempt']['submissiongroupmemberswhoneedtosubmit']);
1990         $this->assertEquals('notgraded', $result['lastattempt']['gradingstatus']);
1992         // Check new attempt reopened.
1993         $this->assertEquals($student1->id, $result['lastattempt']['submission']['userid']);
1994         $this->assertEquals(1, $result['lastattempt']['submission']['attemptnumber']);
1995         $this->assertEquals('reopened', $result['lastattempt']['submission']['status']);
1996         $this->assertEquals(0, $result['lastattempt']['submission']['groupid']);
1997         $this->assertEquals($assign->get_instance()->id, $result['lastattempt']['submission']['assignment']);
1998         $this->assertEquals(1, $result['lastattempt']['submission']['latest']);
1999         $this->assertCount(3, $result['lastattempt']['submission']['plugins']);
2001         // Now see feedback and the attempts history (remember, is a submission reopened).
2002         // Only 2 fields (no grade, no plugins data).
2003         $this->assertCount(2, $result['feedback']);
2005         // One previous attempt.
2006         $this->assertCount(1, $result['previousattempts']);
2007         $this->assertEquals(0, $result['previousattempts'][0]['attemptnumber']);
2008         $this->assertEquals(50, $result['previousattempts'][0]['grade']['grade']);
2009         $this->assertEquals($teacher->id, $result['previousattempts'][0]['grade']['grader']);
2010         $this->assertEquals($student1->id, $result['previousattempts'][0]['grade']['userid']);
2012         // Map plugins based on their type - we can't rely on them being in a
2013         // particular order, especially if 3rd party plugins are installed.
2014         $feedbackplugins = array();
2015         foreach ($result['previousattempts'][0]['feedbackplugins'] as $plugin) {
2016             $feedbackplugins[$plugin['type']] = $plugin;
2017         }
2018         $this->assertEquals('Yeeha!', $feedbackplugins['comments']['editorfields'][0]['text']);
2020         $submissionplugins = array();
2021         foreach ($result['previousattempts'][0]['submission']['plugins'] as $plugin) {
2022             $submissionplugins[$plugin['type']] = $plugin;
2023         }
2024         $this->assertEquals('Submission text', $submissionplugins['onlinetext']['editorfields'][0]['text']);
2025         $this->assertEquals('/t.txt', $submissionplugins['file']['fileareas'][0]['files'][0]['filepath']);
2026     }
2028     /**
2029      * Test access control for get_submission_status.
2030      */
2031     public function test_get_submission_status_access_control() {
2032         $this->resetAfterTest(true);
2034         list($assign, $instance, $student1, $student2, $teacher) = $this->create_submission_for_testing_status();
2036         $this->setUser($student2);
2038         // Access control test.
2039         $this->setExpectedException('required_capability_exception');
2040         mod_assign_external::get_submission_status($assign->get_instance()->id, $student1->id);
2042     }
2044     /**
2045      * get_participant should throw an excaption if the requested assignment doesn't exist.
2046      */
2047     public function test_get_participant_no_assignment() {
2048         $this->resetAfterTest(true);
2049         $this->setExpectedException('moodle_exception');
2050         mod_assign_external::get_participant('-1', '-1', false);
2051     }
2053     /**
2054      * get_participant should throw a require_login_exception if the user doesn't have access
2055      * to view assignments.
2056      */
2057     public function test_get_participant_no_view_capability() {
2058         global $DB;
2059         $this->resetAfterTest(true);
2061         $result = $this->create_assign_with_student_and_teacher();
2062         $assign = $result['assign'];
2063         $student = $result['student'];
2064         $course = $result['course'];
2065         $context = context_course::instance($course->id);
2066         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
2068         $this->setUser($student);
2069         assign_capability('mod/assign:view', CAP_PROHIBIT, $studentrole->id, $context->id, true);
2071         $this->setExpectedException('require_login_exception');
2072         mod_assign_external::get_participant($assign->id, $student->id, false);
2073     }
2075     /**
2076      * get_participant should throw a required_capability_exception if the user doesn't have access
2077      * to view assignment grades.
2078      */
2079     public function test_get_participant_no_grade_capability() {
2080         global $DB;
2081         $this->resetAfterTest(true);
2083         $result = $this->create_assign_with_student_and_teacher();
2084         $assign = $result['assign'];
2085         $student = $result['student'];
2086         $teacher = $result['teacher'];
2087         $course = $result['course'];
2088         $context = context_course::instance($course->id);
2089         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2091         $this->setUser($teacher);
2092         assign_capability('mod/assign:viewgrades', CAP_PROHIBIT, $teacherrole->id, $context->id, true);
2093         assign_capability('mod/assign:grade', CAP_PROHIBIT, $teacherrole->id, $context->id, true);
2094         accesslib_clear_all_caches_for_unit_testing();
2096         $this->setExpectedException('required_capability_exception');
2097         mod_assign_external::get_participant($assign->id, $student->id, false);
2098     }
2100     /**
2101      * get_participant should throw an exception if the user isn't enrolled in the course.
2102      */
2103     public function test_get_participant_no_participant() {
2104         global $DB;
2105         $this->resetAfterTest(true);
2107         $result = $this->create_assign_with_student_and_teacher(array('blindmarking' => true));
2108         $student = $this->getDataGenerator()->create_user();
2109         $assign = $result['assign'];
2110         $teacher = $result['teacher'];
2112         $this->setUser($teacher);
2114         $this->setExpectedException('moodle_exception');
2115         $result = mod_assign_external::get_participant($assign->id, $student->id, false);
2116     }
2118     /**
2119      * get_participant should return a summarised list of details with a different fullname if blind
2120      * marking is on for the requested assignment.
2121      */
2122     public function test_get_participant_blind_marking() {
2123         global $DB;
2124         $this->resetAfterTest(true);
2126         $result = $this->create_assign_with_student_and_teacher(array('blindmarking' => true));
2127         $assign = $result['assign'];
2128         $student = $result['student'];
2129         $teacher = $result['teacher'];
2130         $course = $result['course'];
2131         $context = context_course::instance($course->id);
2132         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2134         $this->setUser($teacher);
2136         $result = mod_assign_external::get_participant($assign->id, $student->id, true);
2137         $this->assertEquals($student->id, $result['id']);
2138         $this->assertFalse(fullname($student) == $result['fullname']);
2139         $this->assertFalse($result['submitted']);
2140         $this->assertFalse($result['requiregrading']);
2141         $this->assertTrue($result['blindmarking']);
2142         // Make sure we don't get any additional info.
2143         $this->assertTrue(empty($result['user']));
2144     }
2146     /**
2147      * get_participant should return a summarised list of details if requested.
2148      */
2149     public function test_get_participant_no_user() {
2150         global $DB;
2151         $this->resetAfterTest(true);
2153         $result = $this->create_assign_with_student_and_teacher();
2154         $assignmodule = $result['assign'];
2155         $student = $result['student'];
2156         $teacher = $result['teacher'];
2157         $course = $result['course'];
2158         $context = context_course::instance($course->id);
2159         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2161         // Create an assign instance to save a submission.
2162         set_config('submissionreceipts', 0, 'assign');
2164         $cm = get_coursemodule_from_instance('assign', $assignmodule->id);
2165         $context = context_module::instance($cm->id);
2167         $assign = new assign($context, $cm, $course);
2169         $this->setUser($student);
2171         // Simulate a submission.
2172         $data = new stdClass();
2173         $data->onlinetext_editor = array(
2174             'itemid' => file_get_unused_draft_itemid(),
2175             'text' => 'Student submission text',
2176             'format' => FORMAT_MOODLE
2177         );
2179         $notices = array();
2180         $assign->save_submission($data, $notices);
2182         $data = new stdClass;
2183         $data->userid = $student->id;
2184         $assign->submit_for_grading($data, array());
2186         $this->setUser($teacher);
2188         $result = mod_assign_external::get_participant($assignmodule->id, $student->id, false);
2189         $this->assertEquals($student->id, $result['id']);
2190         $this->assertEquals(fullname($student), $result['fullname']);
2191         $this->assertTrue($result['submitted']);
2192         $this->assertTrue($result['requiregrading']);
2193         $this->assertFalse($result['blindmarking']);
2194         // Make sure we don't get any additional info.
2195         $this->assertTrue(empty($result['user']));
2196     }
2198     /**
2199      * get_participant should return user details if requested.
2200      */
2201     public function test_get_participant_full_details() {
2202         global $DB;
2203         $this->resetAfterTest(true);
2205         $result = $this->create_assign_with_student_and_teacher();
2206         $assign = $result['assign'];
2207         $student = $result['student'];
2208         $teacher = $result['teacher'];
2209         $course = $result['course'];
2210         $context = context_course::instance($course->id);
2211         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2213         $this->setUser($teacher);
2215         $result = mod_assign_external::get_participant($assign->id, $student->id, true);
2216         // Check some of the extended properties we get when requesting the user.
2217         $this->assertEquals($student->id, $result['id']);
2218         // We should get user infomation back.
2219         $user = $result['user'];
2220         $this->assertFalse(empty($user));
2221         $this->assertEquals($student->firstname, $user['firstname']);
2222         $this->assertEquals($student->lastname, $user['lastname']);
2223         $this->assertEquals($student->email, $user['email']);
2224     }
2226     /**
2227      * get_participant should return group details if a group submission was
2228      * submitted.
2229      */
2230     public function test_get_participant_group_submission() {
2231         global $DB, $CFG;
2232         require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
2234         $this->resetAfterTest(true);
2236         $result = $this->create_assign_with_student_and_teacher(array(
2237             'assignsubmission_onlinetext_enabled' => 1,
2238             'teamsubmission' => 1
2239         ));
2240         $assignmodule = $result['assign'];
2241         $student = $result['student'];
2242         $teacher = $result['teacher'];
2243         $course = $result['course'];
2244         $context = context_course::instance($course->id);
2245         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2246         $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2247         $cm = get_coursemodule_from_instance('assign', $assignmodule->id);
2248         $context = context_module::instance($cm->id);
2249         $assign = new testable_assign($context, $cm, $course);
2251         groups_add_member($group, $student);
2253         $this->setUser($student);
2254         $submission = $assign->get_group_submission($student->id, $group->id, true);
2255         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2256         $assign->testable_update_submission($submission, $student->id, true, false);
2257         $data = new stdClass();
2258         $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
2259                                          'text' => 'Submission text',
2260                                          'format' => FORMAT_MOODLE);
2261         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2262         $plugin->save($submission, $data);
2264         $this->setUser($teacher);
2266         $result = mod_assign_external::get_participant($assignmodule->id, $student->id, false);
2267         // Check some of the extended properties we get when not requesting a summary.
2268         $this->assertEquals($student->id, $result['id']);
2269         $this->assertEquals($group->id, $result['groupid']);
2270         $this->assertEquals($group->name, $result['groupname']);
2271     }
2273     /**
2274      * Test for mod_assign_external::list_participants().
2275      *
2276      * @throws coding_exception
2277      */
2278     public function test_list_participants_user_info_with_special_characters() {
2279         global $CFG, $DB;
2280         $this->resetAfterTest(true);
2281         $CFG->showuseridentity = 'idnumber,email,phone1,phone2,department,institution';
2283         $data = $this->create_assign_with_student_and_teacher();
2284         $assignment = $data['assign'];
2285         $teacher = $data['teacher'];
2287         // Set data for student info that contain special characters.
2288         $student = $data['student'];
2289         $student->idnumber = '<\'"1am@wesome&c00l"\'>';
2290         $student->phone1 = '+63 (999) 888-7777';
2291         $student->phone2 = '(011) [15]4-123-4567';
2292         $student->department = 'Arts & Sciences & \' " ¢ £ © € ¥ ® < >';
2293         $student->institution = 'University of Awesome People & \' " ¢ £ © € ¥ ® < >';
2294         // Assert that we have valid user data.
2295         $this->assertTrue(core_user::validate($student));
2296         // Update the user record.
2297         $DB->update_record('user', $student);
2299         $this->setUser($teacher);
2300         $participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0);
2301         $this->assertCount(1, $participants);
2303         // Asser that we have a valid response data.
2304         $response = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants);
2305         $this->assertEquals($response, $participants);
2307         // Check participant data.
2308         $participant = $participants[0];
2309         $this->assertEquals($student->idnumber, $participant['idnumber']);
2310         $this->assertEquals($student->email, $participant['email']);
2311         $this->assertEquals($student->phone1, $participant['phone1']);
2312         $this->assertEquals($student->phone2, $participant['phone2']);
2313         $this->assertEquals($student->department, $participant['department']);
2314         $this->assertEquals($student->institution, $participant['institution']);
2315     }
2317     /**
2318      * Test for the type of the user-related properties in mod_assign_external::list_participants_returns().
2319      */
2320     public function test_list_participants_returns_user_property_types() {
2321         // Get user properties.
2322         $userdesc = core_user_external::user_description();
2323         $this->assertTrue(isset($userdesc->keys));
2324         $userproperties = array_keys($userdesc->keys);
2326         // Get returns description for mod_assign_external::list_participants_returns().
2327         $listreturns = mod_assign_external::list_participants_returns();
2328         $this->assertTrue(isset($listreturns->content));
2329         $listreturnsdesc = $listreturns->content->keys;
2331         // Iterate over list returns description's keys.
2332         foreach ($listreturnsdesc as $key => $desc) {
2333             // Check if key exists in user properties and the description has a type attribute.
2334             if (in_array($key, $userproperties) && isset($desc->type)) {
2335                 try {
2336                     // The core_user::get_property_type() method might throw a coding_exception since
2337                     // core_user_external::user_description() might contain properties that are not yet included in
2338                     // core_user's $propertiescache.
2339                     $propertytype = core_user::get_property_type($key);
2341                     // Assert that user-related property types match those of the defined in core_user.
2342                     $this->assertEquals($propertytype, $desc->type);
2343                 } catch (coding_exception $e) {
2344                     // All good.
2345                 }
2346             }
2347         }
2348     }
2350     /**
2351      * Create a a course, assignment module instance, student and teacher and enrol them in
2352      * the course.
2353      *
2354      * @param array $params parameters to be provided to the assignment module creation
2355      * @return array containing the course, assignment module, student and teacher
2356      */
2357     private function create_assign_with_student_and_teacher($params = array()) {
2358         global $DB;
2360         $course = $this->getDataGenerator()->create_course();
2361         $params = array_merge(array(
2362             'course' => $course->id,
2363             'name' => 'assignment',
2364             'intro' => 'assignment intro text',
2365         ), $params);
2367         // Create a course and assignment and users.
2368         $assign = $this->getDataGenerator()->create_module('assign', $params);
2370         $cm = get_coursemodule_from_instance('assign', $assign->id);
2371         $context = context_module::instance($cm->id);
2373         $student = $this->getDataGenerator()->create_user();
2374         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
2375         $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id);
2376         $teacher = $this->getDataGenerator()->create_user();
2377         $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2378         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
2380         assign_capability('mod/assign:view', CAP_ALLOW, $teacherrole->id, $context->id, true);
2381         assign_capability('mod/assign:viewgrades', CAP_ALLOW, $teacherrole->id, $context->id, true);
2382         assign_capability('mod/assign:grade', CAP_ALLOW, $teacherrole->id, $context->id, true);
2383         accesslib_clear_all_caches_for_unit_testing();
2385         return array(
2386             'course' => $course,
2387             'assign' => $assign,
2388             'student' => $student,
2389             'teacher' => $teacher
2390         );
2391     }