MDL-38047 Assignment unit tests - Shave 1 minute from the unit tests for mod_assign.
[moodle.git] / mod / assign / tests / locallib_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Unit tests for (some of) mod/assign/locallib.php.
19  *
20  * @package    mod_assign
21  * @category   phpunit
22  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
30 require_once($CFG->dirroot . '/mod/assign/locallib.php');
31 require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
33 /**
34  * Unit tests for (some of) mod/assign/locallib.php.
35  *
36  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
37  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38  */
39 class mod_assign_locallib_testcase extends advanced_testcase {
41     /** @const Default number of students to create */
42     const DEFAULT_STUDENT_COUNT = 3;
43     /** @const Default number of teachers to create */
44     const DEFAULT_TEACHER_COUNT = 2;
45     /** @const Default number of editing teachers to create */
46     const DEFAULT_EDITING_TEACHER_COUNT = 2;
47     /** @const Optional extra number of students to create */
48     const EXTRA_STUDENT_COUNT = 40;
49     /** @const Optional extra number of teachers to create */
50     const EXTRA_TEACHER_COUNT = 5;
51     /** @const Optional extra number of editing teachers to create */
52     const EXTRA_EDITING_TEACHER_COUNT = 5;
53     /** @const Number of groups to create */
54     const GROUP_COUNT = 6;
56     /** @var stdClass $course New course created to hold the assignments */
57     protected $course = null;
59     /** @var array $teachers List of DEFAULT_TEACHER_COUNT teachers in the course*/
60     protected $teachers = null;
62     /** @var array $editingteachers List of DEFAULT_EDITING_TEACHER_COUNT editing teachers in the course */
63     protected $editingteachers = null;
65     /** @var array $students List of DEFAULT_STUDENT_COUNT students in the course*/
66     protected $students = null;
68     /** @var array $extrateachers List of EXTRA_TEACHER_COUNT teachers in the course*/
69     protected $extrateachers = null;
71     /** @var array $extraeditingteachers List of EXTRA_EDITING_TEACHER_COUNT editing teachers in the course*/
72     protected $extraeditingteachers = null;
74     /** @var array $extrastudents List of EXTRA_STUDENT_COUNT students in the course*/
75     protected $extrastudents = null;
77     /** @var array $groups List of 10 groups in the course */
78     protected $groups = null;
80     /**
81      * Setup function - we will create a course and add an assign instance to it.
82      */
83     protected function setUp() {
84         global $DB;
86         $this->resetAfterTest(true);
88         $this->course = $this->getDataGenerator()->create_course();
89         $this->teachers = array();
90         for ($i = 0; $i < self::DEFAULT_TEACHER_COUNT; $i++) {
91             array_push($this->teachers, $this->getDataGenerator()->create_user());
92         }
94         $this->editingteachers = array();
95         for ($i = 0; $i < self::DEFAULT_EDITING_TEACHER_COUNT; $i++) {
96             array_push($this->editingteachers, $this->getDataGenerator()->create_user());
97         }
99         $this->students = array();
100         for ($i = 0; $i < self::DEFAULT_STUDENT_COUNT; $i++) {
101             array_push($this->students, $this->getDataGenerator()->create_user());
102         }
104         $this->groups = array();
105         for ($i = 0; $i < self::GROUP_COUNT; $i++) {
106             array_push($this->groups, $this->getDataGenerator()->create_group(array('courseid'=>$this->course->id)));
107         }
109         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
110         foreach ($this->teachers as $i => $teacher) {
111             $this->getDataGenerator()->enrol_user($teacher->id,
112                                                   $this->course->id,
113                                                   $teacherrole->id);
114             groups_add_member($this->groups[$i % self::GROUP_COUNT], $teacher);
115         }
117         $editingteacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'));
118         foreach ($this->editingteachers as $i => $editingteacher) {
119             $this->getDataGenerator()->enrol_user($editingteacher->id,
120                                                   $this->course->id,
121                                                   $editingteacherrole->id);
122             groups_add_member($this->groups[$i % self::GROUP_COUNT], $editingteacher);
123         }
125         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
126         foreach ($this->students as $i => $student) {
127             $this->getDataGenerator()->enrol_user($student->id,
128                                                   $this->course->id,
129                                                   $studentrole->id);
130             groups_add_member($this->groups[$i % self::GROUP_COUNT], $student);
131         }
132     }
134     /*
135      * For tests that make sense to use alot of data, create extra students/teachers.
136      */
137     private function createExtraUsers() {
138         global $DB;
139         $this->extrateachers = array();
140         for ($i = 0; $i < self::EXTRA_TEACHER_COUNT; $i++) {
141             array_push($this->extrateachers, $this->getDataGenerator()->create_user());
142         }
144         $this->extraeditingteachers = array();
145         for ($i = 0; $i < self::EXTRA_EDITING_TEACHER_COUNT; $i++) {
146             array_push($this->extraeditingteachers, $this->getDataGenerator()->create_user());
147         }
149         $this->extrastudents = array();
150         for ($i = 0; $i < self::EXTRA_STUDENT_COUNT; $i++) {
151             array_push($this->extrastudents, $this->getDataGenerator()->create_user());
152         }
154         $teacherrole = $DB->get_record('role', array('shortname'=>'teacher'));
155         foreach ($this->extrateachers as $i => $teacher) {
156             $this->getDataGenerator()->enrol_user($teacher->id,
157                                                   $this->course->id,
158                                                   $teacherrole->id);
159             groups_add_member($this->groups[$i % self::GROUP_COUNT], $teacher);
160         }
162         $editingteacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'));
163         foreach ($this->extraeditingteachers as $i => $editingteacher) {
164             $this->getDataGenerator()->enrol_user($editingteacher->id,
165                                                   $this->course->id,
166                                                   $editingteacherrole->id);
167             groups_add_member($this->groups[$i % self::GROUP_COUNT], $editingteacher);
168         }
170         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
171         foreach ($this->extrastudents as $i => $student) {
172             $this->getDataGenerator()->enrol_user($student->id,
173                                                   $this->course->id,
174                                                   $studentrole->id);
175             if ($i < (self::EXTRA_STUDENT_COUNT / 2)) {
176                 groups_add_member($this->groups[$i % self::GROUP_COUNT], $student);
177             }
178         }
180     }
182     private function create_instance($params=array()) {
183         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
184         $params['course'] = $this->course->id;
185         $instance = $generator->create_instance($params);
186         $cm = get_coursemodule_from_instance('assign', $instance->id);
187         $context = context_module::instance($cm->id);
188         return new testable_assign($context, $cm, $this->course);
189     }
191     public function test_return_links() {
192         $this->setUser($this->editingteachers[0]);
193         $returnaction = 'RETURNACTION';
194         $returnparams = array('param'=>1);
195         $assign = $this->create_instance();
196         $assign->register_return_link($returnaction, $returnparams);
197         $this->assertEquals($returnaction, $assign->get_return_action());
198         $this->assertEquals($returnparams, $assign->get_return_params());
199     }
201     public function test_get_feedback_plugins() {
202         $this->setUser($this->editingteachers[0]);
203         $assign = $this->create_instance();
204         $this->assertEquals(3, count($assign->get_feedback_plugins()));
205     }
207     public function test_get_submission_plugins() {
208         $this->setUser($this->editingteachers[0]);
209         $assign = $this->create_instance();
210         $this->assertEquals(3, count($assign->get_submission_plugins()));
211     }
213     public function test_is_blind_marking() {
214         $this->setUser($this->editingteachers[0]);
215         $assign = $this->create_instance(array('blindmarking'=>1));
216         $this->assertEquals(true, $assign->is_blind_marking());
218         // Test cannot see student names.
219         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
220         $output = $assign->get_renderer()->render($gradingtable);
221         $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign')));
223         // Test students cannot reveal identities.
224         $nopermission = false;
225         $this->setUser($this->students[0]);
226         $this->setExpectedException('required_capability_exception');
227         $assign->testable_process_reveal_identities();
229         // Test teachers cannot reveal identities.
230         $nopermission = false;
231         $this->setUser($this->teachers[0]);
232         $this->setExpectedException('required_capability_exception');
233         $assign->testable_process_reveal_identities();
235         // Test sesskey is required.
236         $nosesskey = true;
237         $this->setUser($this->editingteachers[0]);
238         $this->setExpectedException('moodle_exception');
239         $assign->testable_process_reveal_identities();
241         // Test editingteacher can reveal identities if sesskey is ignored.
242         $this->editingteachers[0]->ignoresesskey = true;
243         $this->setUser($this->editingteachers[0]);
244         $assign->testable_process_reveal_identities();
245         $this->assertEquals(false, $assign->is_blind_marking());
247         // Test student names are visible.
248         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
249         $output = $assign->get_renderer()->render($gradingtable);
250         $this->assertEquals(false, strpos($output, get_string('hiddenuser', 'assign')));
252         // Set this back to default.
253         $this->editingteachers[0]->ignoresesskey = false;
254     }
256     public function test_show_intro() {
257         // Test whether we are showing the intro at the correct times.
258         $this->setUser($this->editingteachers[0]);
259         $assign = $this->create_instance(array('alwaysshowdescription'=>1));
261         $this->assertEquals(true, $assign->testable_show_intro());
263         $tomorrow = time() + (24*60*60);
265         $assign = $this->create_instance(array('alwaysshowdescription'=>0,
266                                                'allowsubmissionsfromdate'=>$tomorrow));
267         $this->assertEquals(false, $assign->testable_show_intro());
268         $yesterday = time() - (24*60*60);
269         $assign = $this->create_instance(array('alwaysshowdescription'=>0,
270                                                'allowsubmissionsfromdate'=>$yesterday));
271         $this->assertEquals(true, $assign->testable_show_intro());
272     }
274     public function test_has_submissions_or_grades() {
275         $this->setUser($this->editingteachers[0]);
276         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
278         $instance = $assign->get_instance();
280         // Should start empty.
281         $this->assertEquals(false, $assign->has_submissions_or_grades());
283         // Simulate a submission.
284         $this->setUser($this->students[0]);
285         $submission = $assign->get_user_submission($this->students[0]->id, true);
286         $data = new stdClass();
287         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
288                                          'text'=>'Submission text',
289                                          'format'=>FORMAT_MOODLE);
290         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
291         $plugin->save($submission, $data);
293         // Now test again.
294         $this->assertEquals(true, $assign->has_submissions_or_grades());
295         // Set this back to default.
296         $this->students[0]->ignoresesskey = false;
297     }
299     public function test_delete_grades() {
300         $this->setUser($this->editingteachers[0]);
301         $assign = $this->create_instance();
303         // Simulate adding a grade.
304         $this->setUser($this->teachers[0]);
305         $data = new stdClass();
306         $data->grade = '50.0';
307         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
309         // Now see if the data is in the gradebook.
310         $gradinginfo = grade_get_grades($this->course->id,
311                                         'mod',
312                                         'assign',
313                                         $assign->get_instance()->id);
315         $this->assertNotEquals(0, count($gradinginfo->items));
317         $assign->testable_delete_grades();
318         $gradinginfo = grade_get_grades($this->course->id,
319                                         'mod',
320                                         'assign',
321                                         $assign->get_instance()->id);
323         $this->assertEquals(0, count($gradinginfo->items));
324     }
326     public function test_delete_instance() {
327         $this->setUser($this->editingteachers[0]);
328         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
330         // Simulate adding a grade.
331         $this->setUser($this->teachers[0]);
332         $data = new stdClass();
333         $data->grade = '50.0';
334         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
336         // Simulate a submission.
337         $this->setUser($this->students[0]);
338         $submission = $assign->get_user_submission($this->students[0]->id, true);
339         $data = new stdClass();
340         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
341                                          'text'=>'Submission text',
342                                          'format'=>FORMAT_MOODLE);
343         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
344         $plugin->save($submission, $data);
346         // Now try and delete.
347         $this->assertEquals(true, $assign->delete_instance());
348     }
350     public function test_reset_userdata() {
351         global $DB;
353         $now = time();
354         $this->setUser($this->editingteachers[0]);
355         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
356                                                'duedate'=>$now));
358         // Simulate adding a grade.
359         $this->setUser($this->teachers[0]);
360         $data = new stdClass();
361         $data->grade = '50.0';
362         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
364         // Simulate a submission.
365         $this->setUser($this->students[0]);
366         $submission = $assign->get_user_submission($this->students[0]->id, true);
367         $data = new stdClass();
368         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
369                                          'text'=>'Submission text',
370                                          'format'=>FORMAT_MOODLE);
371         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
372         $plugin->save($submission, $data);
374         $this->assertEquals(true, $assign->has_submissions_or_grades());
375         // Now try and reset.
376         $data = new stdClass();
377         $data->reset_assign_submissions = 1;
378         $data->reset_gradebook_grades = 1;
379         $data->courseid = $this->course->id;
380         $data->timeshift = 24*60*60;
381         $this->setUser($this->editingteachers[0]);
382         $assign->reset_userdata($data);
383         $this->assertEquals(false, $assign->has_submissions_or_grades());
385         // Reload the instance data.
386         $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
387         $this->assertEquals($now + 24*60*60, $instance->duedate);
388     }
390     public function test_plugin_settings() {
391         global $DB;
393         $now = time();
394         $this->setUser($this->editingteachers[0]);
395         $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
396                                                'assignsubmission_file_maxfiles'=>12,
397                                                'assignsubmission_file_maxsizebytes'=>10));
399         $plugin = $assign->get_submission_plugin_by_type('file');
400         $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
401     }
403     public function test_update_calendar() {
404         global $DB;
406         $now = time();
407         $this->setUser($this->editingteachers[0]);
408         $assign = $this->create_instance(array('duedate'=>$now));
410         // See if there is an event in the calendar.
411         $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
412         $id = $DB->get_field('event', 'id', $params);
414         $this->assertEquals(false, empty($id));
415     }
417     public function test_update_instance() {
418         global $DB;
420         $this->setUser($this->editingteachers[0]);
421         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
423         $now = time();
424         $instance = $assign->get_instance();
425         $instance->duedate = $now;
426         $instance->instance = $instance->id;
427         $instance->assignsubmission_onlinetext_enabled = 1;
428         $instance->assignsubmission_file_enabled = 0;
429         $instance->assignsubmission_comments_enabled = 0;
430         $instance->assignfeedback_comments_enabled = 0;
431         $instance->assignfeedback_file_enabled = 0;
432         $instance->assignfeedback_offline_enabled = 0;
434         $assign->update_instance($instance);
436         $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
437         $this->assertEquals($now, $instance->duedate);
438     }
440     public function test_list_participants() {
441         $this->createExtraUsers();
442         $this->setUser($this->editingteachers[0]);
443         $assign = $this->create_instance(array('grade'=>100));
445         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
446     }
448     public function test_count_teams() {
449         $this->createExtraUsers();
450         $this->setUser($this->editingteachers[0]);
451         $assign = $this->create_instance(array('teamsubmission'=>1));
453         $this->assertEquals(self::GROUP_COUNT + 1, $assign->count_teams());
454     }
456     public function test_count_submissions() {
457         $this->createExtraUsers();
458         $this->setUser($this->editingteachers[0]);
459         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
461         // Simulate a submission.
462         $this->setUser($this->extrastudents[0]);
463         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
464         // Leave this one as DRAFT.
465         $data = new stdClass();
466         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
467                                          'text'=>'Submission text',
468                                          'format'=>FORMAT_MOODLE);
469         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
470         $plugin->save($submission, $data);
472         // Simulate adding a grade.
473         $this->setUser($this->teachers[0]);
474         $data = new stdClass();
475         $data->grade = '50.0';
476         $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id);
478         // Simulate a submission.
479         $this->setUser($this->extrastudents[1]);
480         $submission = $assign->get_user_submission($this->extrastudents[1]->id, true);
481         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
482         $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
483         $data = new stdClass();
484         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
485                                          'text'=>'Submission text',
486                                          'format'=>FORMAT_MOODLE);
487         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
488         $plugin->save($submission, $data);
490         // Simulate a submission.
491         $this->setUser($this->extrastudents[2]);
492         $submission = $assign->get_user_submission($this->extrastudents[2]->id, true);
493         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
494         $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
495         $data = new stdClass();
496         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
497                                          'text'=>'Submission text',
498                                          'format'=>FORMAT_MOODLE);
499         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
500         $plugin->save($submission, $data);
502         // Simulate a submission.
503         $this->setUser($this->extrastudents[3]);
504         $submission = $assign->get_user_submission($this->extrastudents[3]->id, true);
505         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
506         $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
507         $data = new stdClass();
508         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
509                                          'text'=>'Submission text',
510                                          'format'=>FORMAT_MOODLE);
511         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
512         $plugin->save($submission, $data);
514         // Simulate adding a grade.
515         $this->setUser($this->teachers[0]);
516         $data = new stdClass();
517         $data->grade = '50.0';
518         $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id);
520         $this->assertEquals(2, $assign->count_grades());
521         $this->assertEquals(4, $assign->count_submissions());
522         $this->assertEquals(2, $assign->count_submissions_need_grading());
523         $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
524         $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
525     }
527     public function test_get_grading_userid_list() {
528         $this->createExtraUsers();
529         $this->setUser($this->editingteachers[0]);
530         $assign = $this->create_instance();
532         $users = $assign->testable_get_grading_userid_list();
533         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
534     }
536     public function test_cron() {
537         // First run cron so there are no messages waiting to be sent (from other tests).
538         cron_setup_user();
539         assign::cron();
541         // Now create an assignment and add some feedback.
542         $this->setUser($this->editingteachers[0]);
543         $assign = $this->create_instance();
545         // Simulate adding a grade.
546         $this->setUser($this->teachers[0]);
547         $data = new stdClass();
548         $data->grade = '50.0';
549         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
551         // Now run cron and see that one message was sent.
552         $this->preventResetByRollback();
553         $sink = $this->redirectMessages();
554         cron_setup_user();
555         $this->expectOutputRegex('/Done processing 1 assignment submissions/');
556         assign::cron();
558         $messages = $sink->get_messages();
559         $this->assertEquals(1, count($messages));
560         $this->assertEquals(1, $messages[0]->notification);
561         $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
562     }
564     public function test_is_graded() {
565         $this->setUser($this->editingteachers[0]);
566         $assign = $this->create_instance();
568         // Simulate adding a grade.
569         $this->setUser($this->teachers[0]);
570         $data = new stdClass();
571         $data->grade = '50.0';
572         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
574         $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
575         $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
576     }
578     public function test_can_view_submission() {
579         $this->setUser($this->editingteachers[0]);
580         $assign = $this->create_instance();
582         $this->setUser($this->students[0]);
583         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
584         $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
585         $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
586         $this->setUser($this->teachers[0]);
587         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
588         $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
589         $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
590         $this->setUser($this->editingteachers[0]);
591         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
592         $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
593         $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
594     }
597     public function test_update_submission() {
598         $this->createExtraUsers();
599         $this->setUser($this->editingteachers[0]);
600         $assign = $this->create_instance();
602         $this->setUser($this->extrastudents[0]);
603         $now = time();
604         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
605         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
607         $this->setUser($this->teachers[0]);
608         // Verify the gradebook update.
609         $gradinginfo = grade_get_grades($this->course->id,
610                                         'mod',
611                                         'assign',
612                                         $assign->get_instance()->id,
613                                         $this->extrastudents[0]->id);
615         $this->assertEquals($this->extrastudents[0]->id,
616                             $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
618         // Now verify group assignments.
619         $this->setUser($this->editingteachers[0]);
620         $assign = $this->create_instance(array('teamsubmission'=>1));
622         $this->setUser($this->extrastudents[0]);
623         $now = time();
624         $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
625         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
627         // Check that at least 2 members of the submission group had their submission updated.
629         $this->setUser($this->editingteachers[0]);
630         $gradinginfo = grade_get_grades($this->course->id,
631                                         'mod',
632                                         'assign',
633                                         $assign->get_instance()->id,
634                                         $this->extrastudents[0]->id);
636         $this->assertEquals($this->extrastudents[0]->id,
637                             $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
639         $gradinginfo = grade_get_grades($this->course->id,
640                                         'mod',
641                                         'assign',
642                                         $assign->get_instance()->id,
643                                         $this->extrastudents[self::GROUP_COUNT]->id);
645         $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
646                             $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
648         // Now verify blind marking.
649         $this->setUser($this->editingteachers[0]);
650         $assign = $this->create_instance(array('blindmarking'=>1));
652         $this->setUser($this->extrastudents[0]);
653         $now = time();
654         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
655         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
657         $this->setUser($this->editingteachers[0]);
658         $gradinginfo = grade_get_grades($this->course->id,
659                                         'mod',
660                                         'assign',
661                                         $assign->get_instance()->id,
662                                         $this->extrastudents[0]->id);
664         $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
665     }
667     public function test_submissions_open() {
668         $this->setUser($this->editingteachers[0]);
670         $now = time();
671         $tomorrow = $now + 24*60*60;
672         $oneweek = $now + 7*24*60*60;
673         $yesterday = $now - 24*60*60;
675         $assign = $this->create_instance();
676         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
678         $assign = $this->create_instance(array('duedate'=>$tomorrow));
679         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
681         $assign = $this->create_instance(array('duedate'=>$yesterday));
682         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
684         $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
685         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
687         $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
688         $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
690         $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
691         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
693         $assign = $this->create_instance(array('submissiondrafts'=>1));
694         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
696         $this->setUser($this->students[0]);
697         $now = time();
698         $submission = $assign->get_user_submission($this->students[0]->id, true);
699         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
700         $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
701         $this->setUser($this->editingteachers[0]);
702         $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
703     }
705     public function test_get_graders() {
706         $this->createExtraUsers();
707         $this->setUser($this->editingteachers[0]);
708         $assign = $this->create_instance();
710         $this->assertCount(self::DEFAULT_TEACHER_COUNT +
711                            self::DEFAULT_EDITING_TEACHER_COUNT +
712                            self::EXTRA_TEACHER_COUNT +
713                            self::EXTRA_EDITING_TEACHER_COUNT,
714                            $assign->testable_get_graders($this->students[0]->id));
716         $assign = $this->create_instance();
717         // Force create an assignment with SEPARATEGROUPS.
718         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
719         $params = array('course'=>$this->course->id);
720         $instance = $generator->create_instance($params);
721         $cm = get_coursemodule_from_instance('assign', $instance->id);
722         set_coursemodule_groupmode($cm->id, SEPARATEGROUPS);
723         $cm->groupmode = SEPARATEGROUPS;
724         $context = context_module::instance($cm->id);
725         $assign = new testable_assign($context, $cm, $this->course);
727         $this->setUser($this->students[1]);
728         $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
729     }
731     public function test_get_uniqueid_for_user() {
732         $this->setUser($this->editingteachers[0]);
733         $assign = $this->create_instance();
735         foreach ($this->students as $student) {
736             $uniqueid = $assign->get_uniqueid_for_user($student->id);
737             $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
738         }
739     }
741     public function test_show_student_summary() {
742         global $CFG;
744         $this->setUser($this->editingteachers[0]);
745         $assign = $this->create_instance();
747         // No feedback should be available because this student has not been graded.
748         $this->setUser($this->students[0]);
749         $output = $assign->view_student_summary($this->students[0], true);
750         $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
751         // Simulate adding a grade.
752         $this->setUser($this->teachers[0]);
753         $data = new stdClass();
754         $data->grade = '50.0';
755         $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
757         // Now we should see the feedback
758         $this->setUser($this->students[0]);
759         $output = $assign->view_student_summary($this->students[0], true);
760         $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
762         // Now hide the grade in gradebook.
763         $this->setUser($this->teachers[0]);
764         require_once($CFG->libdir.'/gradelib.php');
765         $gradeitem = new grade_item(array(
766             'itemtype'      => 'mod',
767             'itemmodule'    => 'assign',
768             'iteminstance'  => $assign->get_instance()->id,
769             'courseid'      => $this->course->id));
771         $gradeitem->set_hidden(1, false);
773         // No feedback should be available because the grade is hidden.
774         $this->setUser($this->students[0]);
775         $output = $assign->view_student_summary($this->students[0], true);
776         $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
778         // Do the same but add feedback
779         $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
781         $this->setUser($this->teachers[0]);
782         $grade = $assign->get_user_grade($this->students[0]->id, true);
783         $data = new stdClass();
784         $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
785                                          'format'=>FORMAT_MOODLE);
786         $plugin = $assign->get_feedback_plugin_by_type('comments');
787         $plugin->save($grade, $data);
789         // Should have feedback but no grade
790         $this->setUser($this->students[0]);
791         $output = $assign->view_student_summary($this->students[0], true);
792         $this->assertNotEquals(false, strpos($output, 'Tomato sauce'), 'Show feedback even if there is no grade');
793         $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
794         $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
795     }
800 /**
801  * Test subclass that makes all the protected methods we want to test public.
802  */
803 class testable_assign extends assign {
805     public function testable_process_reveal_identities() {
806         return parent::process_reveal_identities();
807     }
809     public function testable_show_intro() {
810         return parent::show_intro();
811     }
813     public function testable_delete_grades() {
814         return parent::delete_grades();
815     }
817     public function testable_apply_grade_to_user($formdata, $userid) {
818         return parent::apply_grade_to_user($formdata, $userid);
819     }
821     public function testable_get_grading_userid_list() {
822         return parent::get_grading_userid_list();
823     }
825     public function testable_is_graded($userid) {
826         return parent::is_graded($userid);
827     }
829     public function testable_update_submission(stdClass $submission, $userid, $updatetime, $teamsubmission) {
830         return parent::update_submission($submission, $userid, $updatetime, $teamsubmission);
831     }
833     public function testable_submissions_open($userid = 0) {
834         return parent::submissions_open($userid);
835     }
837     public function testable_save_user_extension($userid, $extensionduedate) {
838         return parent::save_user_extension($userid, $extensionduedate);
839     }
841     public function testable_get_graders($userid) {
842         // Changed method from protected to public.
843         return parent::get_graders($userid);
844     }