Merge branch 'MDL-37148-master' of git://github.com/damyon/moodle
[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');
32 require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
34 /**
35  * Unit tests for (some of) mod/assign/locallib.php.
36  *
37  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  */
40 class mod_assign_locallib_testcase extends mod_assign_base_testcase {
42     public function test_return_links() {
43         global $PAGE;
44         $this->setUser($this->editingteachers[0]);
45         $returnaction = 'RETURNACTION';
46         $returnparams = array('param'=>'1');
47         $assign = $this->create_instance();
48         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
49         $assign->register_return_link($returnaction, $returnparams);
50         $this->assertEquals($returnaction, $assign->get_return_action());
51         $this->assertEquals($returnparams, $assign->get_return_params());
52     }
54     public function test_get_feedback_plugins() {
55         $this->setUser($this->editingteachers[0]);
56         $assign = $this->create_instance();
57         $installedplugins = array_keys(core_component::get_plugin_list('assignfeedback'));
59         foreach ($assign->get_feedback_plugins() as $plugin) {
60             $this->assertContains($plugin->get_type(), $installedplugins, 'Feedback plugin not in list of installed plugins');
61         }
62     }
64     public function test_get_submission_plugins() {
65         $this->setUser($this->editingteachers[0]);
66         $assign = $this->create_instance();
67         $installedplugins = array_keys(core_component::get_plugin_list('assignsubmission'));
69         foreach ($assign->get_submission_plugins() as $plugin) {
70             $this->assertContains($plugin->get_type(), $installedplugins, 'Submission plugin not in list of installed plugins');
71         }
72     }
74     public function test_is_blind_marking() {
75         $this->setUser($this->editingteachers[0]);
76         $assign = $this->create_instance(array('blindmarking'=>1));
77         $this->assertEquals(true, $assign->is_blind_marking());
79         // Test cannot see student names.
80         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
81         $output = $assign->get_renderer()->render($gradingtable);
82         $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign')));
84         // Test students cannot reveal identities.
85         $nopermission = false;
86         $this->students[0]->ignoresesskey = true;
87         $this->setUser($this->students[0]);
88         $this->setExpectedException('required_capability_exception');
89         $assign->reveal_identities();
90         $this->students[0]->ignoresesskey = false;
92         // Test teachers cannot reveal identities.
93         $nopermission = false;
94         $this->teachers[0]->ignoresesskey = true;
95         $this->setUser($this->teachers[0]);
96         $this->setExpectedException('required_capability_exception');
97         $assign->reveal_identities();
98         $this->teachers[0]->ignoresesskey = false;
100         // Test sesskey is required.
101         $this->setUser($this->editingteachers[0]);
102         $this->setExpectedException('moodle_exception');
103         $assign->reveal_identities();
105         // Test editingteacher can reveal identities if sesskey is ignored.
106         $this->editingteachers[0]->ignoresesskey = true;
107         $this->setUser($this->editingteachers[0]);
108         $assign->reveal_identities();
109         $this->assertEquals(false, $assign->is_blind_marking());
110         $this->editingteachers[0]->ignoresesskey = false;
112         // Test student names are visible.
113         $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
114         $output = $assign->get_renderer()->render($gradingtable);
115         $this->assertEquals(false, strpos($output, get_string('hiddenuser', 'assign')));
117         // Set this back to default.
118         $this->editingteachers[0]->ignoresesskey = false;
119     }
121     public function test_show_intro() {
122         // Test whether we are showing the intro at the correct times.
123         $this->setUser($this->editingteachers[0]);
124         $assign = $this->create_instance(array('alwaysshowdescription'=>1));
126         $this->assertEquals(true, $assign->testable_show_intro());
128         $tomorrow = time() + (24*60*60);
130         $assign = $this->create_instance(array('alwaysshowdescription'=>0,
131                                                'allowsubmissionsfromdate'=>$tomorrow));
132         $this->assertEquals(false, $assign->testable_show_intro());
133         $yesterday = time() - (24*60*60);
134         $assign = $this->create_instance(array('alwaysshowdescription'=>0,
135                                                'allowsubmissionsfromdate'=>$yesterday));
136         $this->assertEquals(true, $assign->testable_show_intro());
137     }
139     public function test_has_submissions_or_grades() {
140         $this->setUser($this->editingteachers[0]);
141         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
143         $instance = $assign->get_instance();
145         // Should start empty.
146         $this->assertEquals(false, $assign->has_submissions_or_grades());
148         // Simulate a submission.
149         $this->setUser($this->students[0]);
150         $submission = $assign->get_user_submission($this->students[0]->id, true);
151         $data = new stdClass();
152         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
153                                          'text'=>'Submission text',
154                                          'format'=>FORMAT_MOODLE);
155         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
156         $plugin->save($submission, $data);
158         // Now test again.
159         $this->assertEquals(true, $assign->has_submissions_or_grades());
160         // Set this back to default.
161         $this->students[0]->ignoresesskey = false;
162     }
164     public function test_delete_grades() {
165         $this->setUser($this->editingteachers[0]);
166         $assign = $this->create_instance();
168         // Simulate adding a grade.
169         $this->setUser($this->teachers[0]);
170         $data = new stdClass();
171         $data->grade = '50.0';
172         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
174         // Now see if the data is in the gradebook.
175         $gradinginfo = grade_get_grades($this->course->id,
176                                         'mod',
177                                         'assign',
178                                         $assign->get_instance()->id);
180         $this->assertNotEquals(0, count($gradinginfo->items));
182         $assign->testable_delete_grades();
183         $gradinginfo = grade_get_grades($this->course->id,
184                                         'mod',
185                                         'assign',
186                                         $assign->get_instance()->id);
188         $this->assertEquals(0, count($gradinginfo->items));
189     }
191     public function test_delete_instance() {
192         $this->setUser($this->editingteachers[0]);
193         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
195         // Simulate adding a grade.
196         $this->setUser($this->teachers[0]);
197         $data = new stdClass();
198         $data->grade = '50.0';
199         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
201         // Simulate a submission.
202         $this->setUser($this->students[0]);
203         $submission = $assign->get_user_submission($this->students[0]->id, true);
204         $data = new stdClass();
205         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
206                                          'text'=>'Submission text',
207                                          'format'=>FORMAT_MOODLE);
208         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
209         $plugin->save($submission, $data);
211         // Now try and delete.
212         $this->assertEquals(true, $assign->delete_instance());
213     }
215     public function test_reset_userdata() {
216         global $DB;
218         $now = time();
219         $this->setUser($this->editingteachers[0]);
220         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
221                                                'duedate'=>$now));
223         // Simulate adding a grade.
224         $this->setUser($this->teachers[0]);
225         $data = new stdClass();
226         $data->grade = '50.0';
227         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
229         // Simulate a submission.
230         $this->setUser($this->students[0]);
231         $submission = $assign->get_user_submission($this->students[0]->id, true);
232         $data = new stdClass();
233         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
234                                          'text'=>'Submission text',
235                                          'format'=>FORMAT_MOODLE);
236         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
237         $plugin->save($submission, $data);
239         $this->assertEquals(true, $assign->has_submissions_or_grades());
240         // Now try and reset.
241         $data = new stdClass();
242         $data->reset_assign_submissions = 1;
243         $data->reset_gradebook_grades = 1;
244         $data->courseid = $this->course->id;
245         $data->timeshift = 24*60*60;
246         $this->setUser($this->editingteachers[0]);
247         $assign->reset_userdata($data);
248         $this->assertEquals(false, $assign->has_submissions_or_grades());
250         // Reload the instance data.
251         $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
252         $this->assertEquals($now + 24*60*60, $instance->duedate);
253     }
255     public function test_plugin_settings() {
256         global $DB;
258         $now = time();
259         $this->setUser($this->editingteachers[0]);
260         $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
261                                                'assignsubmission_file_maxfiles'=>12,
262                                                'assignsubmission_file_maxsizebytes'=>10));
264         $plugin = $assign->get_submission_plugin_by_type('file');
265         $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
266     }
268     public function test_update_calendar() {
269         global $DB;
271         $now = time();
272         $this->setUser($this->editingteachers[0]);
273         $assign = $this->create_instance(array('duedate'=>$now));
275         // See if there is an event in the calendar.
276         $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
277         $id = $DB->get_field('event', 'id', $params);
279         $this->assertEquals(false, empty($id));
280     }
282     public function test_update_instance() {
283         global $DB;
285         $this->setUser($this->editingteachers[0]);
286         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
288         $now = time();
289         $instance = $assign->get_instance();
290         $instance->duedate = $now;
291         $instance->instance = $instance->id;
292         $instance->assignsubmission_onlinetext_enabled = 1;
294         $assign->update_instance($instance);
296         $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
297         $this->assertEquals($now, $instance->duedate);
298     }
300     public function test_cannot_submit_empty() {
301         global $PAGE;
303         $this->setUser($this->editingteachers[0]);
304         $assign = $this->create_instance(array('submissiondrafts'=>1));
306         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
308         // Test you cannot see the submit button for an offline assignment regardless.
309         $this->setUser($this->students[0]);
310         $output = $assign->view_student_summary($this->students[0], true);
311         $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
313         // Test you cannot see the submit button for an online text assignment with no submission.
314         $this->setUser($this->editingteachers[0]);
315         $instance = $assign->get_instance();
316         $instance->instance = $instance->id;
317         $instance->assignsubmission_onlinetext_enabled = 1;
319         $assign->update_instance($instance);
320         $this->setUser($this->students[0]);
321         $output = $assign->view_student_summary($this->students[0], true);
322         $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
324         // Simulate a submission.
325         $submission = $assign->get_user_submission($this->students[0]->id, true);
326         $data = new stdClass();
327         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
328                                          'text'=>'Submission text',
329                                          'format'=>FORMAT_MOODLE);
330         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
331         $plugin->save($submission, $data);
332         // Test you can see the submit button for an online text assignment with a submission.
333         $output = $assign->view_student_summary($this->students[0], true);
334         $this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
335     }
337     public function test_list_participants() {
338         $this->create_extra_users();
339         $this->setUser($this->editingteachers[0]);
340         $assign = $this->create_instance(array('grade'=>100));
342         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
344         // Teacher with user preference set should see suspended users as well.
345         set_user_preference('grade_report_showonlyactiveenrol', false);
346         $assign = $this->create_instance(array('grade'=>100));
347         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
348                 count($assign->list_participants(null, true)));
350         // Non-editing teacher should not see suspended users, even if user preference is set.
351         $this->setUser($this->teachers[0]);
352         set_user_preference('grade_report_showonlyactiveenrol', false);
353         $assign = $this->create_instance(array('grade'=>100));
354         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
355     }
357     public function test_count_teams() {
358         $this->create_extra_users();
359         $this->setUser($this->editingteachers[0]);
360         $assign = $this->create_instance(array('teamsubmission'=>1));
362         $this->assertEquals(self::GROUP_COUNT + 1, $assign->count_teams());
363     }
365     public function test_count_submissions() {
366         $this->create_extra_users();
367         $this->setUser($this->editingteachers[0]);
368         $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
370         // Simulate a submission.
371         $this->setUser($this->extrastudents[0]);
372         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
373         // Leave this one as DRAFT.
374         $data = new stdClass();
375         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
376                                          'text'=>'Submission text',
377                                          'format'=>FORMAT_MOODLE);
378         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
379         $plugin->save($submission, $data);
381         // Simulate adding a grade.
382         $this->setUser($this->teachers[0]);
383         $data = new stdClass();
384         $data->grade = '50.0';
385         $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
387         // Simulate a submission.
388         $this->setUser($this->extrastudents[1]);
389         $submission = $assign->get_user_submission($this->extrastudents[1]->id, true);
390         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
391         $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
392         $data = new stdClass();
393         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
394                                          'text'=>'Submission text',
395                                          'format'=>FORMAT_MOODLE);
396         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
397         $plugin->save($submission, $data);
399         // Simulate a submission.
400         $this->setUser($this->extrastudents[2]);
401         $submission = $assign->get_user_submission($this->extrastudents[2]->id, true);
402         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
403         $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
404         $data = new stdClass();
405         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
406                                          'text'=>'Submission text',
407                                          'format'=>FORMAT_MOODLE);
408         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
409         $plugin->save($submission, $data);
411         // Simulate a submission.
412         $this->setUser($this->extrastudents[3]);
413         $submission = $assign->get_user_submission($this->extrastudents[3]->id, true);
414         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
415         $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
416         $data = new stdClass();
417         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
418                                          'text'=>'Submission text',
419                                          'format'=>FORMAT_MOODLE);
420         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
421         $plugin->save($submission, $data);
423         // Simulate a submission for suspended user, this will never be counted.
424         $this->setUser($this->extrastudents[3]);
425         $submission = $assign->get_user_submission($this->extrasuspendedstudents[0]->id, true);
426         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
427         $assign->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
428         $data = new stdClass();
429         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
430                                          'text'=>'Submission text',
431                                          'format'=>FORMAT_MOODLE);
432         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
433         $plugin->save($submission, $data);
435         // Simulate adding a grade.
436         $this->setUser($this->teachers[0]);
437         $data = new stdClass();
438         $data->grade = '50.0';
439         $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
440         $assign->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
442         $this->assertEquals(2, $assign->count_grades());
443         $this->assertEquals(4, $assign->count_submissions());
444         $this->assertEquals(2, $assign->count_submissions_need_grading());
445         $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
446         $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
447     }
449     public function test_get_grading_userid_list() {
450         $this->create_extra_users();
451         $this->setUser($this->editingteachers[0]);
452         $assign = $this->create_instance();
454         $users = $assign->testable_get_grading_userid_list();
455         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
457         $this->setUser($this->editingteachers[0]);
458         set_user_preference('grade_report_showonlyactiveenrol', false);
459         $assign = $this->create_instance();
461         $users = $assign->testable_get_grading_userid_list();
462         $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
463     }
465     public function test_cron() {
466         // First run cron so there are no messages waiting to be sent (from other tests).
467         cron_setup_user();
468         assign::cron();
470         // Now create an assignment and add some feedback.
471         $this->setUser($this->editingteachers[0]);
472         $assign = $this->create_instance();
474         // Simulate adding a grade.
475         $this->setUser($this->teachers[0]);
476         $data = new stdClass();
477         $data->grade = '50.0';
478         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
480         // Now run cron and see that one message was sent.
481         $this->preventResetByRollback();
482         $sink = $this->redirectMessages();
483         cron_setup_user();
484         $this->expectOutputRegex('/Done processing 1 assignment submissions/');
485         assign::cron();
487         $messages = $sink->get_messages();
488         $this->assertEquals(1, count($messages));
489         $this->assertEquals(1, $messages[0]->notification);
490         $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
491     }
493     public function test_is_graded() {
494         $this->setUser($this->editingteachers[0]);
495         $assign = $this->create_instance();
497         // Simulate adding a grade.
498         $this->setUser($this->teachers[0]);
499         $data = new stdClass();
500         $data->grade = '50.0';
501         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
503         $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
504         $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
505     }
507     public function test_can_view_submission() {
508         $this->create_extra_users();
509         $this->setUser($this->editingteachers[0]);
510         $assign = $this->create_instance();
512         $this->setUser($this->students[0]);
513         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
514         $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
515         $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
516         $this->setUser($this->teachers[0]);
517         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
518         $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
519         $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
520         $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
521         $this->setUser($this->editingteachers[0]);
522         $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
523         $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
524         $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
525         $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
526     }
529     public function test_update_submission() {
530         $this->create_extra_users();
531         $this->setUser($this->editingteachers[0]);
532         $assign = $this->create_instance();
534         $this->setUser($this->extrastudents[0]);
535         $now = time();
536         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
537         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
539         $this->setUser($this->teachers[0]);
540         // Verify the gradebook update.
541         $gradinginfo = grade_get_grades($this->course->id,
542                                         'mod',
543                                         'assign',
544                                         $assign->get_instance()->id,
545                                         $this->extrastudents[0]->id);
547         $this->assertEquals($this->extrastudents[0]->id,
548                             $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
550         // Now verify group assignments.
551         $this->setUser($this->editingteachers[0]);
552         $assign = $this->create_instance(array('teamsubmission'=>1));
554         $this->setUser($this->extrastudents[0]);
555         $now = time();
556         $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
557         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
559         // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
561         $this->setUser($this->editingteachers[0]);
562         $gradinginfo = grade_get_grades($this->course->id,
563                                         'mod',
564                                         'assign',
565                                         $assign->get_instance()->id,
566                                         $this->extrastudents[0]->id);
568         $this->assertEquals($this->extrastudents[0]->id,
569                             $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
571         $gradinginfo = grade_get_grades($this->course->id,
572                                         'mod',
573                                         'assign',
574                                         $assign->get_instance()->id,
575                                         $this->extrastudents[self::GROUP_COUNT]->id);
577         $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
578                             $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
580         $gradinginfo = grade_get_grades($this->course->id,
581                                         'mod',
582                                         'assign',
583                                         $assign->get_instance()->id,
584                                         $this->extrasuspendedstudents[0]->id);
585         $this->assertEquals($this->extrasuspendedstudents[0]->id,
586                             $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
588         // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
589         $this->setUser($this->editingteachers[0]);
590         $assign = $this->create_instance(array('teamsubmission'=>1));
592         $this->setUser($this->extrastudents[1]);
593         $now = time();
594         $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
595         $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
597         $this->setUser($this->teachers[0]);
598         $gradinginfo = grade_get_grades($this->course->id,
599                                         'mod',
600                                         'assign',
601                                         $assign->get_instance()->id,
602                                         $this->extrastudents[1]->id);
604         $this->assertEquals($this->extrastudents[1]->id,
605                             $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
607         $gradinginfo = grade_get_grades($this->course->id,
608                                         'mod',
609                                         'assign',
610                                         $assign->get_instance()->id,
611                                         $this->extrastudents[self::GROUP_COUNT+1]->id);
613         $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
614                             $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
616         $gradinginfo = grade_get_grades($this->course->id,
617                                         'mod',
618                                         'assign',
619                                         $assign->get_instance()->id,
620                                         $this->extrasuspendedstudents[1]->id);
621         $this->assertEquals($this->extrasuspendedstudents[1]->id,
622                             $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
624         // Now verify blind marking.
625         $this->setUser($this->editingteachers[0]);
626         $assign = $this->create_instance(array('blindmarking'=>1));
628         $this->setUser($this->extrastudents[0]);
629         $now = time();
630         $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
631         $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
633         $this->setUser($this->editingteachers[0]);
634         $gradinginfo = grade_get_grades($this->course->id,
635                                         'mod',
636                                         'assign',
637                                         $assign->get_instance()->id,
638                                         $this->extrastudents[0]->id);
640         $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
641     }
643     public function test_submissions_open() {
644         $this->setUser($this->editingteachers[0]);
646         $now = time();
647         $tomorrow = $now + 24*60*60;
648         $oneweek = $now + 7*24*60*60;
649         $yesterday = $now - 24*60*60;
651         $assign = $this->create_instance();
652         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
654         $assign = $this->create_instance(array('duedate'=>$tomorrow));
655         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
657         $assign = $this->create_instance(array('duedate'=>$yesterday));
658         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
660         $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
661         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
663         $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
664         $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
666         $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
667         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
669         $assign = $this->create_instance(array('submissiondrafts'=>1));
670         $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
672         $this->setUser($this->students[0]);
673         $now = time();
674         $submission = $assign->get_user_submission($this->students[0]->id, true);
675         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
676         $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
677         $this->setUser($this->editingteachers[0]);
678         $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
679     }
681     public function test_get_graders() {
682         $this->create_extra_users();
683         $this->setUser($this->editingteachers[0]);
684         $assign = $this->create_instance();
686         $this->assertCount(self::DEFAULT_TEACHER_COUNT +
687                            self::DEFAULT_EDITING_TEACHER_COUNT +
688                            self::EXTRA_TEACHER_COUNT +
689                            self::EXTRA_EDITING_TEACHER_COUNT,
690                            $assign->testable_get_graders($this->students[0]->id));
692         $assign = $this->create_instance();
693         // Force create an assignment with SEPARATEGROUPS.
694         $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
695         $params = array('course'=>$this->course->id);
696         $instance = $generator->create_instance($params);
697         $cm = get_coursemodule_from_instance('assign', $instance->id);
698         set_coursemodule_groupmode($cm->id, SEPARATEGROUPS);
699         $cm->groupmode = SEPARATEGROUPS;
700         $context = context_module::instance($cm->id);
701         $assign = new testable_assign($context, $cm, $this->course);
703         $this->setUser($this->students[1]);
704         $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
705     }
707     public function test_group_members_only() {
708         global $CFG;
710         $this->setAdminUser();
711         $this->create_extra_users();
712         $CFG->enablegroupmembersonly = true;
713         $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
714         groups_assign_grouping($grouping->id, $this->groups[0]->id);
716         // Force create an assignment with SEPARATEGROUPS.
717         $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
718             array('groupmembersonly' => SEPARATEGROUPS, 'groupingid' => $grouping->id));
720         $cm = get_coursemodule_from_instance('assign', $instance->id);
721         $context = context_module::instance($cm->id);
722         $assign = new testable_assign($context, $cm, $this->course);
724         $this->setUser($this->teachers[0]);
725         $this->assertCount(5, $assign->list_participants(0, true));
727     }
729     public function test_get_uniqueid_for_user() {
730         $this->setUser($this->editingteachers[0]);
731         $assign = $this->create_instance();
733         foreach ($this->students as $student) {
734             $uniqueid = $assign->get_uniqueid_for_user($student->id);
735             $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
736         }
737     }
739     public function test_show_student_summary() {
740         global $CFG, $PAGE;
742         $this->setUser($this->editingteachers[0]);
743         $assign = $this->create_instance();
744         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
746         // No feedback should be available because this student has not been graded.
747         $this->setUser($this->students[0]);
748         $output = $assign->view_student_summary($this->students[0], true);
749         $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
750         // Simulate adding a grade.
751         $this->setUser($this->teachers[0]);
752         $data = new stdClass();
753         $data->grade = '50.0';
754         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
756         // Now we should see the feedback.
757         $this->setUser($this->students[0]);
758         $output = $assign->view_student_summary($this->students[0], true);
759         $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
761         // Now hide the grade in gradebook.
762         $this->setUser($this->teachers[0]);
763         require_once($CFG->libdir.'/gradelib.php');
764         $gradeitem = new grade_item(array(
765             'itemtype'      => 'mod',
766             'itemmodule'    => 'assign',
767             'iteminstance'  => $assign->get_instance()->id,
768             'courseid'      => $this->course->id));
770         $gradeitem->set_hidden(1, false);
772         // No feedback should be available because the grade is hidden.
773         $this->setUser($this->students[0]);
774         $output = $assign->view_student_summary($this->students[0], true);
775         $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
777         // Do the same but add feedback.
778         $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
780         $this->setUser($this->teachers[0]);
781         $grade = $assign->get_user_grade($this->students[0]->id, true);
782         $data = new stdClass();
783         $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
784                                          'format'=>FORMAT_MOODLE);
785         $plugin = $assign->get_feedback_plugin_by_type('comments');
786         $plugin->save($grade, $data);
788         // Should have feedback but no grade.
789         $this->setUser($this->students[0]);
790         $output = $assign->view_student_summary($this->students[0], true);
791         $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
792         $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
793         $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
795         // Now hide the grade in gradebook.
796         $this->setUser($this->teachers[0]);
797         $gradeitem = new grade_item(array(
798             'itemtype'      => 'mod',
799             'itemmodule'    => 'assign',
800             'iteminstance'  => $assign->get_instance()->id,
801             'courseid'      => $this->course->id));
803         $gradeitem->set_hidden(1, false);
805         // No feedback should be available because the grade is hidden.
806         $this->setUser($this->students[0]);
807         $output = $assign->view_student_summary($this->students[0], true);
808         $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
809     }
811     public function test_attempt_reopen_method_manual() {
812         global $PAGE;
814         $this->setUser($this->editingteachers[0]);
815         $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
816                                                'maxattempts'=>3,
817                                                'submissiondrafts'=>1,
818                                                'assignsubmission_onlinetext_enabled'=>1));
819         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
821         // Student should be able to see an add submission button.
822         $this->setUser($this->students[0]);
823         $output = $assign->view_student_summary($this->students[0], true);
824         $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
826         // Add a submission.
827         $now = time();
828         $submission = $assign->get_user_submission($this->students[0]->id, true);
829         $data = new stdClass();
830         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
831                                          'text'=>'Submission text',
832                                          'format'=>FORMAT_MOODLE);
833         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
834         $plugin->save($submission, $data);
836         // And now submit it for marking.
837         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
838         $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
840         // Verify the student cannot make changes to the submission.
841         $output = $assign->view_student_summary($this->students[0], true);
842         $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
844         // Mark the submission.
845         $this->setUser($this->teachers[0]);
846         $data = new stdClass();
847         $data->grade = '50.0';
848         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
850         // Check the student can see the grade.
851         $this->setUser($this->students[0]);
852         $output = $assign->view_student_summary($this->students[0], true);
853         $this->assertNotEquals(false, strpos($output, '50.0'));
855         // Allow the student another attempt.
856         $this->teachers[0]->ignoresesskey = true;
857         $this->setUser($this->teachers[0]);
858         $result = $assign->testable_process_add_attempt($this->students[0]->id);
859         $this->assertEquals(true, $result);
861         // Check that the previous attempt is now in the submission history table.
862         $this->setUser($this->students[0]);
863         $output = $assign->view_student_summary($this->students[0], true);
864         // Need a better check.
865         $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
867         // Check that the student now has a button for Add a new attempt".
868         $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
869         // Check that the student now does not have a button for Submit.
870         $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
872         // Check that the student now has a submission history.
873         $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
875         $this->setUser($this->teachers[0]);
876         // Check that the grading table loads correctly and contains this user.
877         // This is also testing that we do not get duplicate rows in the grading table.
878         $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
879         $output = $assign->get_renderer()->render($gradingtable);
880         $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
882         // Should be 1 not 2.
883         $this->assertEquals(1, $assign->count_submissions());
884         $this->assertEquals(1, $assign->count_submissions_with_status('reopened'));
885         $this->assertEquals(0, $assign->count_submissions_need_grading());
886         $this->assertEquals(1, $assign->count_grades());
888         // Change max attempts to unlimited.
889         $formdata = clone($assign->get_instance());
890         $formdata->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS;
891         $formdata->instance = $formdata->id;
892         $assign->update_instance($formdata);
894         // Check we can repopen still.
895         $result = $assign->testable_process_add_attempt($this->students[0]->id);
896         $this->assertEquals(true, $result);
898         $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
899         $this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
901     }
903     public function test_markingworkflow() {
904         global $PAGE;
906         $this->setUser($this->editingteachers[0]);
907         $assign = $this->create_instance(array('markingworkflow'=>1));
908         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
910         // Mark the submission and set to notmarked.
911         $this->setUser($this->teachers[0]);
912         $data = new stdClass();
913         $data->grade = '50.0';
914         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
915         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
917         // Check the student can't see the grade.
918         $this->setUser($this->students[0]);
919         $output = $assign->view_student_summary($this->students[0], true);
920         $this->assertEquals(false, strpos($output, '50.0'));
922         // Mark the submission and set to inmarking.
923         $this->setUser($this->teachers[0]);
924         $data = new stdClass();
925         $data->grade = '50.0';
926         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
927         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
929         // Check the student can't see the grade.
930         $this->setUser($this->students[0]);
931         $output = $assign->view_student_summary($this->students[0], true);
932         $this->assertEquals(false, strpos($output, '50.0'));
934         // Mark the submission and set to readyforreview.
935         $this->setUser($this->teachers[0]);
936         $data = new stdClass();
937         $data->grade = '50.0';
938         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
939         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
941         // Check the student can't see the grade.
942         $this->setUser($this->students[0]);
943         $output = $assign->view_student_summary($this->students[0], true);
944         $this->assertEquals(false, strpos($output, '50.0'));
946         // Mark the submission and set to inreview.
947         $this->setUser($this->teachers[0]);
948         $data = new stdClass();
949         $data->grade = '50.0';
950         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
951         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
953         // Check the student can't see the grade.
954         $this->setUser($this->students[0]);
955         $output = $assign->view_student_summary($this->students[0], true);
956         $this->assertEquals(false, strpos($output, '50.0'));
958         // Mark the submission and set to readyforrelease.
959         $this->setUser($this->teachers[0]);
960         $data = new stdClass();
961         $data->grade = '50.0';
962         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
963         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
965         // Check the student can't see the grade.
966         $this->setUser($this->students[0]);
967         $output = $assign->view_student_summary($this->students[0], true);
968         $this->assertEquals(false, strpos($output, '50.0'));
970         // Mark the submission and set to released.
971         $this->setUser($this->teachers[0]);
972         $data = new stdClass();
973         $data->grade = '50.0';
974         $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
975         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
977         // Check the student can see the grade.
978         $this->setUser($this->students[0]);
979         $output = $assign->view_student_summary($this->students[0], true);
980         $this->assertNotEquals(false, strpos($output, '50.0'));
981     }
983     public function test_markerallocation() {
984         global $PAGE;
986         $this->setUser($this->editingteachers[0]);
987         $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
988         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
990         // Allocate marker to submission.
991         $data = new stdClass();
992         $data->allocatedmarker = $this->teachers[0]->id;
993         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
995         // Check the allocated marker can view the submission.
996         $this->setUser($this->teachers[0]);
997         $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
998         $output = $assign->get_renderer()->render($gradingtable);
999         $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1001         // Check that other teachers can't view this submission.
1002         $this->setUser($this->teachers[1]);
1003         $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1004         $output = $assign->get_renderer()->render($gradingtable);
1005         $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
1006     }
1008     public function test_extension_granted_event() {
1009         $this->setUser($this->editingteachers[0]);
1011         $tomorrow = time() + 24*60*60;
1012         $yesterday = time() - 24*60*60;
1014         $assign = $this->create_instance(array('duedate' => $yesterday, 'cutoffdate' => $yesterday));
1015         $sink = $this->redirectEvents();
1017         $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
1019         $events = $sink->get_events();
1020         $this->assertCount(1, $events);
1021         $event = reset($events);
1022         $this->assertInstanceOf('\mod_assign\event\extension_granted', $event);
1023         $this->assertEquals($assign->get_context(), $event->get_context());
1024         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1025         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1026         $expected = array(
1027             $assign->get_course()->id,
1028             'assign',
1029             'grant extension',
1030             'view.php?id=' . $assign->get_course_module()->id,
1031             $this->students[0]->id,
1032             $assign->get_course_module()->id,
1033             $this->editingteachers[0]->id
1034         );
1035         $this->assertEventLegacyLogData($expected, $event);
1036         $sink->close();
1037     }
1039     public function test_submission_locked_event() {
1040         $this->editingteachers[0]->ignoresesskey = true;
1041         $this->setUser($this->editingteachers[0]);
1043         $assign = $this->create_instance();
1044         $sink = $this->redirectEvents();
1046         $assign->lock_submission($this->students[0]->id);
1048         $events = $sink->get_events();
1049         $this->assertCount(1, $events);
1050         $event = reset($events);
1051         $this->assertInstanceOf('\mod_assign\event\submission_locked', $event);
1052         $this->assertEquals($assign->get_context(), $event->get_context());
1053         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1054         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1055         $expected = array(
1056             $assign->get_course()->id,
1057             'assign',
1058             'lock submission',
1059             'view.php?id=' . $assign->get_course_module()->id,
1060             get_string('locksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
1061                 'fullname' => fullname($this->students[0]))),
1062             $assign->get_course_module()->id,
1063             $this->editingteachers[0]->id
1064         );
1065         $this->assertEventLegacyLogData($expected, $event);
1066         $sink->close();
1068         // Revert to defaults.
1069         $this->editingteachers[0]->ignoresesskey = false;
1070     }
1072     public function test_identities_revealed_event() {
1073         $this->editingteachers[0]->ignoresesskey = true;
1074         $this->setUser($this->editingteachers[0]);
1076         $assign = $this->create_instance(array('blindmarking'=>1));
1077         $sink = $this->redirectEvents();
1079         $assign->reveal_identities();
1081         $events = $sink->get_events();
1082         $this->assertCount(1, $events);
1083         $event = reset($events);
1084         $this->assertInstanceOf('\mod_assign\event\identities_revealed', $event);
1085         $this->assertEquals($assign->get_context(), $event->get_context());
1086         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1087         $expected = array(
1088             $assign->get_course()->id,
1089             'assign',
1090             'reveal identities',
1091             'view.php?id=' . $assign->get_course_module()->id,
1092             get_string('revealidentities', 'assign'),
1093             $assign->get_course_module()->id,
1094             $this->editingteachers[0]->id
1095         );
1096         $this->assertEventLegacyLogData($expected, $event);
1097         $sink->close();
1099         // Revert to defaults.
1100         $this->editingteachers[0]->ignoresesskey = false;
1101     }
1103     public function test_submission_status_updated_event() {
1104         $this->editingteachers[0]->ignoresesskey = true;
1105         $this->setUser($this->editingteachers[0]);
1107         $assign = $this->create_instance();
1108         $submission = $assign->get_user_submission($this->students[0]->id, true);
1109         $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1110         $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1112         $sink = $this->redirectEvents();
1113         $assign->revert_to_draft($this->students[0]->id);
1115         $events = $sink->get_events();
1116         $this->assertCount(1, $events);
1117         $event = reset($events);
1118         $this->assertInstanceOf('\mod_assign\event\submission_status_updated', $event);
1119         $this->assertEquals($assign->get_context(), $event->get_context());
1120         $this->assertEquals($submission->id, $event->objectid);
1121         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1122         $this->assertEquals(ASSIGN_SUBMISSION_STATUS_DRAFT, $event->other['newstatus']);
1123         $expected = array(
1124             $assign->get_course()->id,
1125             'assign',
1126             'revert submission to draft',
1127             'view.php?id=' . $assign->get_course_module()->id,
1128             get_string('reverttodraftforstudent', 'assign', array('id' => $this->students[0]->id,
1129                 'fullname' => fullname($this->students[0]))),
1130             $assign->get_course_module()->id,
1131             $this->editingteachers[0]->id
1132         );
1133         $this->assertEventLegacyLogData($expected, $event);
1134         $sink->close();
1136         // Revert to defaults.
1137         $this->editingteachers[0]->ignoresesskey = false;
1138     }
1140     public function test_marker_updated_event() {
1141         $this->editingteachers[0]->ignoresesskey = true;
1142         $this->setUser($this->editingteachers[0]);
1144         $assign = $this->create_instance();
1146         $sink = $this->redirectEvents();
1147         $assign->testable_process_set_batch_marking_allocation($this->students[0]->id, $this->teachers[0]->id);
1149         $events = $sink->get_events();
1150         $this->assertCount(1, $events);
1151         $event = reset($events);
1152         $this->assertInstanceOf('\mod_assign\event\marker_updated', $event);
1153         $this->assertEquals($assign->get_context(), $event->get_context());
1154         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1155         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1156         $this->assertEquals($this->editingteachers[0]->id, $event->userid);
1157         $this->assertEquals($this->teachers[0]->id, $event->other['markerid']);
1158         $expected = array(
1159             $assign->get_course()->id,
1160             'assign',
1161             'set marking allocation',
1162             'view.php?id=' . $assign->get_course_module()->id,
1163             get_string('setmarkerallocationforlog', 'assign', array('id' => $this->students[0]->id,
1164                 'fullname' => fullname($this->students[0]), 'marker' => fullname($this->teachers[0]))),
1165             $assign->get_course_module()->id,
1166             $this->editingteachers[0]->id
1167         );
1168         $this->assertEventLegacyLogData($expected, $event);
1169         $sink->close();
1171         // Revert to defaults.
1172         $this->editingteachers[0]->ignoresesskey = false;
1173     }
1175     public function test_workflow_state_updated_event() {
1176         $this->editingteachers[0]->ignoresesskey = true;
1177         $this->setUser($this->editingteachers[0]);
1179         $assign = $this->create_instance();
1181         $sink = $this->redirectEvents();
1182         $assign->testable_process_set_batch_marking_workflow_state($this->students[0]->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
1184         $events = $sink->get_events();
1185         $this->assertCount(1, $events);
1186         $event = reset($events);
1187         $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
1188         $this->assertEquals($assign->get_context(), $event->get_context());
1189         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1190         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1191         $this->assertEquals($this->editingteachers[0]->id, $event->userid);
1192         $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW, $event->other['newstate']);
1193         $expected = array(
1194             $assign->get_course()->id,
1195             'assign',
1196             'set marking workflow state',
1197             'view.php?id=' . $assign->get_course_module()->id,
1198             get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
1199                 'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
1200             $assign->get_course_module()->id,
1201             $this->editingteachers[0]->id
1202         );
1203         $this->assertEventLegacyLogData($expected, $event);
1204         $sink->close();
1206         // Revert to defaults.
1207         $this->editingteachers[0]->ignoresesskey = false;
1208     }
1210     public function test_submission_duplicated_event() {
1211         $this->setUser($this->students[0]);
1213         $assign = $this->create_instance();
1214         $submission1 = $assign->get_user_submission($this->students[0]->id, true, 0);
1215         $submission2 = $assign->get_user_submission($this->students[0]->id, true, 1);
1216         $submission2->status = ASSIGN_SUBMISSION_STATUS_REOPENED;
1217         $assign->testable_update_submission($submission2, $this->students[0]->id, time(), $assign->get_instance()->teamsubmission);
1219         $sink = $this->redirectEvents();
1220         $notices = null;
1221         $assign->copy_previous_attempt($notices);
1223         $events = $sink->get_events();
1224         $this->assertCount(1, $events);
1225         $event = reset($events);
1226         $this->assertInstanceOf('\mod_assign\event\submission_duplicated', $event);
1227         $this->assertEquals($assign->get_context(), $event->get_context());
1228         $this->assertEquals($submission2->id, $event->objectid);
1229         $this->assertEquals($this->students[0]->id, $event->userid);
1230         $submission2->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
1231         $expected = array(
1232             $assign->get_course()->id,
1233             'assign',
1234             'submissioncopied',
1235             'view.php?id=' . $assign->get_course_module()->id,
1236             $assign->testable_format_submission_for_log($submission2),
1237             $assign->get_course_module()->id,
1238             $this->students[0]->id
1239         );
1240         $this->assertEventLegacyLogData($expected, $event);
1241         $sink->close();
1242     }
1244     public function test_submission_unlocked_event() {
1245         $this->editingteachers[0]->ignoresesskey = true;
1246         $this->setUser($this->editingteachers[0]);
1248         $assign = $this->create_instance();
1249         $sink = $this->redirectEvents();
1251         $assign->unlock_submission($this->students[0]->id);
1253         $events = $sink->get_events();
1254         $this->assertCount(1, $events);
1255         $event = reset($events);
1256         $this->assertInstanceOf('\mod_assign\event\submission_unlocked', $event);
1257         $this->assertEquals($assign->get_context(), $event->get_context());
1258         $this->assertEquals($assign->get_instance()->id, $event->objectid);
1259         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1260         $expected = array(
1261             $assign->get_course()->id,
1262             'assign',
1263             'unlock submission',
1264             'view.php?id=' . $assign->get_course_module()->id,
1265             get_string('unlocksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
1266                 'fullname' => fullname($this->students[0]))),
1267             $assign->get_course_module()->id,
1268             $this->editingteachers[0]->id
1269         );
1270         $this->assertEventLegacyLogData($expected, $event);
1271         $sink->close();
1273         // Revert to defaults.
1274         $this->editingteachers[0]->ignoresesskey = false;
1275     }
1277     public function test_submission_graded_event() {
1278         $this->setUser($this->editingteachers[0]);
1279         $assign = $this->create_instance();
1281         // Test apply_grade_to_user.
1282         $sink = $this->redirectEvents();
1284         $data = new stdClass();
1285         $data->grade = '50.0';
1286         $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1287         $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
1289         $events = $sink->get_events();
1290         $this->assertCount(1, $events);
1291         $event = reset($events);
1292         $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
1293         $this->assertEquals($assign->get_context(), $event->get_context());
1294         $this->assertEquals($grade->id, $event->objectid);
1295         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1296         $expected = array(
1297             $assign->get_course()->id,
1298             'assign',
1299             'grade submission',
1300             'view.php?id=' . $assign->get_course_module()->id,
1301             $assign->format_grade_for_log($grade),
1302             $assign->get_course_module()->id,
1303             $this->editingteachers[0]->id
1304         );
1305         $this->assertEventLegacyLogData($expected, $event);
1306         $sink->close();
1308         // Test process_save_quick_grades.
1309         $sink = $this->redirectEvents();
1311         $data = array(
1312             'grademodified_' . $this->students[0]->id => time(),
1313             'quickgrade_' . $this->students[0]->id => '60.0'
1314         );
1315         $assign->testable_process_save_quick_grades($data);
1316         $grade = $assign->get_user_grade($this->students[0]->id, false);
1317         $this->assertEquals('60.0', $grade->grade);
1319         $events = $sink->get_events();
1320         $this->assertCount(1, $events);
1321         $event = reset($events);
1322         $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
1323         $this->assertEquals($assign->get_context(), $event->get_context());
1324         $this->assertEquals($grade->id, $event->objectid);
1325         $this->assertEquals($this->students[0]->id, $event->relateduserid);
1326         $expected = array(
1327             $assign->get_course()->id,
1328             'assign',
1329             'grade submission',
1330             'view.php?id=' . $assign->get_course_module()->id,
1331             $assign->format_grade_for_log($grade),
1332             $assign->get_course_module()->id,
1333             $this->editingteachers[0]->id
1334         );
1335         $this->assertEventLegacyLogData($expected, $event);
1336         $sink->close();
1337     }
1339     public function test_disable_submit_after_cutoff_date() {
1340         global $PAGE;
1342         $this->setUser($this->editingteachers[0]);
1343         $now = time();
1344         $tomorrow = $now + 24*60*60;
1345         $lastweek = $now - 7*24*60*60;
1346         $yesterday = $now - 24*60*60;
1348         $assign = $this->create_instance(array('duedate'=>$yesterday,
1349                                                'cutoffdate'=>$tomorrow,
1350                                                'assignsubmission_onlinetext_enabled'=>1));
1351         $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1353         // Student should be able to see an add submission button.
1354         $this->setUser($this->students[0]);
1355         $output = $assign->view_student_summary($this->students[0], true);
1356         $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1358         // Add a submission but don't submit now.
1359         $submission = $assign->get_user_submission($this->students[0]->id, true);
1360         $data = new stdClass();
1361         $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1362                                          'text'=>'Submission text',
1363                                          'format'=>FORMAT_MOODLE);
1364         $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1365         $plugin->save($submission, $data);
1367         // Create another instance with cut-off and due-date already passed.
1368         $this->setUser($this->editingteachers[0]);
1369         $now = time();
1370         $assign = $this->create_instance(array('duedate'=>$lastweek,
1371                                                'cutoffdate'=>$yesterday,
1372                                                'assignsubmission_onlinetext_enabled'=>1));
1374         $this->setUser($this->students[0]);
1375         $output = $assign->view_student_summary($this->students[0], true);
1376         $this->assertNotContains($output, get_string('editsubmission', 'assign'),
1377                                  'Should not be able to edit after cutoff date.');
1378         $this->assertNotContains($output, get_string('submitassignment', 'assign'),
1379                                  'Should not be able to submit after cutoff date.');
1380     }