2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Unit tests for (some of) mod/assign/locallib.php.
22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
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');
35 * Unit tests for (some of) mod/assign/locallib.php.
37 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class mod_assign_locallib_testcase extends mod_assign_base_testcase {
42 public function test_return_links() {
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());
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');
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');
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;
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());
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);
159 $this->assertEquals(true, $assign->has_submissions_or_grades());
160 // Set this back to default.
161 $this->students[0]->ignoresesskey = false;
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,
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,
186 $assign->get_instance()->id);
188 $this->assertEquals(0, count($gradinginfo->items));
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());
215 public function test_reset_userdata() {
219 $this->setUser($this->editingteachers[0]);
220 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
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);
254 // Test reset using assign_reset_userdata().
255 $assignduedate = $instance->duedate; // Keep old updated value for comparison.
256 $data->timeshift = 2*24*60*60;
257 assign_reset_userdata($data);
258 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
259 $this->assertEquals($assignduedate + 2*24*60*60, $instance->duedate);
261 // Create one more assignment and reset, make sure time shifted for previous assignment is not changed.
262 $assign2 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
264 $assignduedate = $instance->duedate;
265 $data->timeshift = 3*24*60*60;
266 $assign2->reset_userdata($data);
267 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
268 $this->assertEquals($assignduedate, $instance->duedate);
269 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
270 $this->assertEquals($now + 3*24*60*60, $instance2->duedate);
272 // Reset both assignments using assign_reset_userdata() and make sure both assignments have same date.
273 $assignduedate = $instance->duedate;
274 $assign2duedate = $instance2->duedate;
275 $data->timeshift = 4*24*60*60;
276 assign_reset_userdata($data);
277 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
278 $this->assertEquals($assignduedate + 4*24*60*60, $instance->duedate);
279 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
280 $this->assertEquals($assign2duedate + 4*24*60*60, $instance2->duedate);
283 public function test_plugin_settings() {
287 $this->setUser($this->editingteachers[0]);
288 $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
289 'assignsubmission_file_maxfiles'=>12,
290 'assignsubmission_file_maxsizebytes'=>10));
292 $plugin = $assign->get_submission_plugin_by_type('file');
293 $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
296 public function test_update_calendar() {
299 $this->setUser($this->editingteachers[0]);
300 $userctx = context_user::instance($this->editingteachers[0]->id)->id;
302 // Hack to pretend that there was an editor involved. We need both $_POST and $_REQUEST, and a sesskey.
303 $draftid = file_get_unused_draft_itemid();
304 $_REQUEST['introeditor'] = $draftid;
305 $_POST['introeditor'] = $draftid;
306 $_POST['sesskey'] = sesskey();
308 // Write links to a draft area.
309 $fakearealink1 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">link</a>', 'draftfile.php', $userctx,
310 'user', 'draft', $draftid);
311 $fakearealink2 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">new</a>', 'draftfile.php', $userctx,
312 'user', 'draft', $draftid);
314 // Create a new assignment with links to a draft area.
316 $assign = $this->create_instance(array(
318 'intro' => $fakearealink1,
319 'introformat' => FORMAT_HTML
322 // See if there is an event in the calendar.
323 $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
324 $event = $DB->get_record('event', $params);
325 $this->assertNotEmpty($event);
326 $this->assertSame('link', $event->description); // The pluginfile links are removed.
328 // Make sure the same works when updating the assignment.
329 $instance = $assign->get_instance();
330 $instance->instance = $instance->id;
331 $instance->intro = $fakearealink2;
332 $instance->introformat = FORMAT_HTML;
333 $assign->update_instance($instance);
334 $params = array('modulename' => 'assign', 'instance' => $assign->get_instance()->id);
335 $event = $DB->get_record('event', $params);
336 $this->assertNotEmpty($event);
337 $this->assertSame('new', $event->description); // The pluginfile links are removed.
340 public function test_update_instance() {
343 $this->setUser($this->editingteachers[0]);
344 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
347 $instance = $assign->get_instance();
348 $instance->duedate = $now;
349 $instance->instance = $instance->id;
350 $instance->assignsubmission_onlinetext_enabled = 1;
352 $assign->update_instance($instance);
354 $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
355 $this->assertEquals($now, $instance->duedate);
358 public function test_cannot_submit_empty() {
361 $this->setUser($this->editingteachers[0]);
362 $assign = $this->create_instance(array('submissiondrafts'=>1));
364 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
366 // Test you cannot see the submit button for an offline assignment regardless.
367 $this->setUser($this->students[0]);
368 $output = $assign->view_student_summary($this->students[0], true);
369 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
371 // Test you cannot see the submit button for an online text assignment with no submission.
372 $this->setUser($this->editingteachers[0]);
373 $instance = $assign->get_instance();
374 $instance->instance = $instance->id;
375 $instance->assignsubmission_onlinetext_enabled = 1;
377 $assign->update_instance($instance);
378 $this->setUser($this->students[0]);
379 $output = $assign->view_student_summary($this->students[0], true);
380 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
382 // Simulate a submission.
383 $submission = $assign->get_user_submission($this->students[0]->id, true);
384 $data = new stdClass();
385 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
386 'text'=>'Submission text',
387 'format'=>FORMAT_MOODLE);
388 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
389 $plugin->save($submission, $data);
390 // Test you can see the submit button for an online text assignment with a submission.
391 $output = $assign->view_student_summary($this->students[0], true);
392 $this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
395 public function test_list_participants() {
396 $this->create_extra_users();
397 $this->setUser($this->editingteachers[0]);
398 $assign = $this->create_instance(array('grade'=>100));
400 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
402 // Teacher with user preference set should see suspended users as well.
403 set_user_preference('grade_report_showonlyactiveenrol', false);
404 $assign = $this->create_instance(array('grade'=>100));
405 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
406 count($assign->list_participants(null, true)));
408 // Non-editing teacher should not see suspended users, even if user preference is set.
409 $this->setUser($this->teachers[0]);
410 set_user_preference('grade_report_showonlyactiveenrol', false);
411 $assign = $this->create_instance(array('grade'=>100));
412 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
415 public function test_count_teams() {
416 $this->create_extra_users();
417 $this->setUser($this->editingteachers[0]);
418 $assign = $this->create_instance(array('teamsubmission'=>1));
420 $this->assertEquals(self::GROUP_COUNT + 1, $assign->count_teams());
423 public function test_count_submissions() {
424 $this->create_extra_users();
425 $this->setUser($this->editingteachers[0]);
426 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
428 // Simulate a submission.
429 $this->setUser($this->extrastudents[0]);
430 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
431 // Leave this one as DRAFT.
432 $data = new stdClass();
433 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
434 'text'=>'Submission text',
435 'format'=>FORMAT_MOODLE);
436 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
437 $plugin->save($submission, $data);
439 // Simulate adding a grade.
440 $this->setUser($this->teachers[0]);
441 $data = new stdClass();
442 $data->grade = '50.0';
443 $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
445 // Simulate a submission.
446 $this->setUser($this->extrastudents[1]);
447 $submission = $assign->get_user_submission($this->extrastudents[1]->id, true);
448 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
449 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
450 $data = new stdClass();
451 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
452 'text'=>'Submission text',
453 'format'=>FORMAT_MOODLE);
454 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
455 $plugin->save($submission, $data);
457 // Simulate a submission.
458 $this->setUser($this->extrastudents[2]);
459 $submission = $assign->get_user_submission($this->extrastudents[2]->id, true);
460 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
461 $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
462 $data = new stdClass();
463 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
464 'text'=>'Submission text',
465 'format'=>FORMAT_MOODLE);
466 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
467 $plugin->save($submission, $data);
469 // Simulate a submission.
470 $this->setUser($this->extrastudents[3]);
471 $submission = $assign->get_user_submission($this->extrastudents[3]->id, true);
472 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
473 $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
474 $data = new stdClass();
475 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
476 'text'=>'Submission text',
477 'format'=>FORMAT_MOODLE);
478 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
479 $plugin->save($submission, $data);
481 // Simulate a submission for suspended user, this will never be counted.
482 $this->setUser($this->extrastudents[3]);
483 $submission = $assign->get_user_submission($this->extrasuspendedstudents[0]->id, true);
484 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
485 $assign->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
486 $data = new stdClass();
487 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
488 'text'=>'Submission text',
489 'format'=>FORMAT_MOODLE);
490 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
491 $plugin->save($submission, $data);
493 // Simulate adding a grade.
494 $this->setUser($this->teachers[0]);
495 $data = new stdClass();
496 $data->grade = '50.0';
497 $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
498 $assign->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
500 $this->assertEquals(2, $assign->count_grades());
501 $this->assertEquals(4, $assign->count_submissions());
502 $this->assertEquals(2, $assign->count_submissions_need_grading());
503 $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
504 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
507 public function test_get_grading_userid_list() {
508 $this->create_extra_users();
509 $this->setUser($this->editingteachers[0]);
510 $assign = $this->create_instance();
512 $users = $assign->testable_get_grading_userid_list();
513 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
515 $this->setUser($this->editingteachers[0]);
516 set_user_preference('grade_report_showonlyactiveenrol', false);
517 $assign = $this->create_instance();
519 $users = $assign->testable_get_grading_userid_list();
520 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
523 public function test_cron() {
524 // First run cron so there are no messages waiting to be sent (from other tests).
528 // Now create an assignment and add some feedback.
529 $this->setUser($this->editingteachers[0]);
530 $assign = $this->create_instance();
532 // Simulate adding a grade.
533 $this->setUser($this->teachers[0]);
534 $data = new stdClass();
535 $data->grade = '50.0';
536 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
537 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
539 // Now run cron and see that one message was sent.
540 $this->preventResetByRollback();
541 $sink = $this->redirectMessages();
543 $this->expectOutputRegex('/Done processing 2 assignment submissions/');
546 $messages = $sink->get_messages();
547 $this->assertEquals(2, count($messages));
548 $this->assertEquals(1, $messages[0]->notification);
549 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
552 public function test_is_graded() {
553 $this->setUser($this->editingteachers[0]);
554 $assign = $this->create_instance();
556 // Simulate adding a grade.
557 $this->setUser($this->teachers[0]);
558 $data = new stdClass();
559 $data->grade = '50.0';
560 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
562 $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
563 $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
566 public function test_can_view_submission() {
567 $this->create_extra_users();
568 $this->setUser($this->editingteachers[0]);
569 $assign = $this->create_instance();
571 $this->setUser($this->students[0]);
572 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
573 $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
574 $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
575 $this->setUser($this->teachers[0]);
576 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
577 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
578 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
579 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
580 $this->setUser($this->editingteachers[0]);
581 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
582 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
583 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
584 $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
588 public function test_update_submission() {
589 $this->create_extra_users();
590 $this->setUser($this->editingteachers[0]);
591 $assign = $this->create_instance();
593 $this->setUser($this->extrastudents[0]);
595 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
596 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
598 $this->setUser($this->teachers[0]);
599 // Verify the gradebook update.
600 $gradinginfo = grade_get_grades($this->course->id,
603 $assign->get_instance()->id,
604 $this->extrastudents[0]->id);
606 $this->assertEquals($this->extrastudents[0]->id,
607 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
609 // Now verify group assignments.
610 $this->setUser($this->editingteachers[0]);
611 $assign = $this->create_instance(array('teamsubmission'=>1));
613 $this->setUser($this->extrastudents[0]);
615 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
616 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
618 // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
620 $this->setUser($this->editingteachers[0]);
621 $gradinginfo = grade_get_grades($this->course->id,
624 $assign->get_instance()->id,
625 $this->extrastudents[0]->id);
627 $this->assertEquals($this->extrastudents[0]->id,
628 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
630 $gradinginfo = grade_get_grades($this->course->id,
633 $assign->get_instance()->id,
634 $this->extrastudents[self::GROUP_COUNT]->id);
636 $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
637 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
639 $gradinginfo = grade_get_grades($this->course->id,
642 $assign->get_instance()->id,
643 $this->extrasuspendedstudents[0]->id);
644 $this->assertEquals($this->extrasuspendedstudents[0]->id,
645 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
647 // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
648 $this->setUser($this->editingteachers[0]);
649 $assign = $this->create_instance(array('teamsubmission'=>1));
651 $this->setUser($this->extrastudents[1]);
653 $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
654 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
656 $this->setUser($this->teachers[0]);
657 $gradinginfo = grade_get_grades($this->course->id,
660 $assign->get_instance()->id,
661 $this->extrastudents[1]->id);
663 $this->assertEquals($this->extrastudents[1]->id,
664 $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
666 $gradinginfo = grade_get_grades($this->course->id,
669 $assign->get_instance()->id,
670 $this->extrastudents[self::GROUP_COUNT+1]->id);
672 $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
673 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
675 $gradinginfo = grade_get_grades($this->course->id,
678 $assign->get_instance()->id,
679 $this->extrasuspendedstudents[1]->id);
680 $this->assertEquals($this->extrasuspendedstudents[1]->id,
681 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
683 // Now verify blind marking.
684 $this->setUser($this->editingteachers[0]);
685 $assign = $this->create_instance(array('blindmarking'=>1));
687 $this->setUser($this->extrastudents[0]);
689 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
690 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
692 $this->setUser($this->editingteachers[0]);
693 $gradinginfo = grade_get_grades($this->course->id,
696 $assign->get_instance()->id,
697 $this->extrastudents[0]->id);
699 $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
702 public function test_group_submissions_submit_for_marking() {
705 $this->create_extra_users();
706 // Now verify group assignments.
707 $this->setUser($this->editingteachers[0]);
708 $assign = $this->create_instance(array('teamsubmission'=>1,
709 'assignsubmission_onlinetext_enabled'=>1,
710 'submissiondrafts'=>1,
711 'requireallteammemberssubmit'=>1));
712 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
714 $this->setUser($this->extrastudents[0]);
716 $data = new stdClass();
717 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
718 'text'=>'Submission text',
719 'format'=>FORMAT_MOODLE);
722 $assign->save_submission($data, $notices);
724 // Check we can see the submit button.
725 $output = $assign->view_student_summary($this->extrastudents[0], true);
726 $this->assertContains(get_string('submitassignment', 'assign'), $output);
728 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
729 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
730 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
732 // Check that the student does not see "Submit" button.
733 $output = $assign->view_student_summary($this->extrastudents[0], true);
734 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
736 // Change to another user in the same group.
737 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
738 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
739 $this->assertContains(get_string('submitassignment', 'assign'), $output);
741 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
742 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
743 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
744 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
745 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
748 public function test_submissions_open() {
749 $this->setUser($this->editingteachers[0]);
752 $tomorrow = $now + 24*60*60;
753 $oneweek = $now + 7*24*60*60;
754 $yesterday = $now - 24*60*60;
756 $assign = $this->create_instance();
757 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
759 $assign = $this->create_instance(array('duedate'=>$tomorrow));
760 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
762 $assign = $this->create_instance(array('duedate'=>$yesterday));
763 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
765 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
766 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
768 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
769 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
771 $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
772 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
774 $assign = $this->create_instance(array('submissiondrafts'=>1));
775 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
777 $this->setUser($this->students[0]);
779 $submission = $assign->get_user_submission($this->students[0]->id, true);
780 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
781 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
782 $this->setUser($this->editingteachers[0]);
783 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
786 public function test_get_graders() {
787 $this->create_extra_users();
788 $this->setUser($this->editingteachers[0]);
790 // Create an assignment with no groups.
791 $assign = $this->create_instance();
792 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
793 self::DEFAULT_EDITING_TEACHER_COUNT +
794 self::EXTRA_TEACHER_COUNT +
795 self::EXTRA_EDITING_TEACHER_COUNT,
796 $assign->testable_get_graders($this->students[0]->id));
798 // Force create an assignment with SEPARATEGROUPS.
799 $data = new stdClass();
800 $data->courseid = $this->course->id;
801 $data->name = 'Grouping';
802 $groupingid = groups_create_grouping($data);
803 groups_assign_grouping($groupingid, $this->groups[0]->id);
804 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
806 $this->setUser($this->students[1]);
807 $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
808 // Note the second student is in a group that is not in the grouping.
809 // This means that we get all graders that are not in a group in the grouping.
810 $this->assertCount(10, $assign->testable_get_graders($this->students[1]->id));
813 public function test_group_members_only() {
816 $this->setAdminUser();
817 $this->create_extra_users();
818 $CFG->enablegroupmembersonly = true;
819 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
820 groups_assign_grouping($grouping->id, $this->groups[0]->id);
822 // Force create an assignment with SEPARATEGROUPS.
823 $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
824 array('groupmembersonly' => SEPARATEGROUPS, 'groupingid' => $grouping->id));
826 $cm = get_coursemodule_from_instance('assign', $instance->id);
827 $context = context_module::instance($cm->id);
828 $assign = new testable_assign($context, $cm, $this->course);
830 $this->setUser($this->teachers[0]);
831 $this->assertCount(5, $assign->list_participants(0, true));
835 public function test_get_uniqueid_for_user() {
836 $this->setUser($this->editingteachers[0]);
837 $assign = $this->create_instance();
839 foreach ($this->students as $student) {
840 $uniqueid = $assign->get_uniqueid_for_user($student->id);
841 $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
845 public function test_show_student_summary() {
848 $this->setUser($this->editingteachers[0]);
849 $assign = $this->create_instance();
850 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
852 // No feedback should be available because this student has not been graded.
853 $this->setUser($this->students[0]);
854 $output = $assign->view_student_summary($this->students[0], true);
855 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
856 // Simulate adding a grade.
857 $this->setUser($this->teachers[0]);
858 $data = new stdClass();
859 $data->grade = '50.0';
860 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
862 // Now we should see the feedback.
863 $this->setUser($this->students[0]);
864 $output = $assign->view_student_summary($this->students[0], true);
865 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
867 // Now hide the grade in gradebook.
868 $this->setUser($this->teachers[0]);
869 require_once($CFG->libdir.'/gradelib.php');
870 $gradeitem = new grade_item(array(
872 'itemmodule' => 'assign',
873 'iteminstance' => $assign->get_instance()->id,
874 'courseid' => $this->course->id));
876 $gradeitem->set_hidden(1, false);
878 // No feedback should be available because the grade is hidden.
879 $this->setUser($this->students[0]);
880 $output = $assign->view_student_summary($this->students[0], true);
881 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
883 // Do the same but add feedback.
884 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
886 $this->setUser($this->teachers[0]);
887 $grade = $assign->get_user_grade($this->students[0]->id, true);
888 $data = new stdClass();
889 $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
890 'format'=>FORMAT_MOODLE);
891 $plugin = $assign->get_feedback_plugin_by_type('comments');
892 $plugin->save($grade, $data);
894 // Should have feedback but no grade.
895 $this->setUser($this->students[0]);
896 $output = $assign->view_student_summary($this->students[0], true);
897 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
898 $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
899 $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
901 // Now hide the grade in gradebook.
902 $this->setUser($this->teachers[0]);
903 $gradeitem = new grade_item(array(
905 'itemmodule' => 'assign',
906 'iteminstance' => $assign->get_instance()->id,
907 'courseid' => $this->course->id));
909 $gradeitem->set_hidden(1, false);
911 // No feedback should be available because the grade is hidden.
912 $this->setUser($this->students[0]);
913 $output = $assign->view_student_summary($this->students[0], true);
914 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
917 public function test_attempt_reopen_method_manual() {
920 $this->setUser($this->editingteachers[0]);
921 $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
923 'submissiondrafts'=>1,
924 'assignsubmission_onlinetext_enabled'=>1));
925 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
927 // Student should be able to see an add submission button.
928 $this->setUser($this->students[0]);
929 $output = $assign->view_student_summary($this->students[0], true);
930 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
934 $submission = $assign->get_user_submission($this->students[0]->id, true);
935 $data = new stdClass();
936 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
937 'text'=>'Submission text',
938 'format'=>FORMAT_MOODLE);
939 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
940 $plugin->save($submission, $data);
942 // And now submit it for marking.
943 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
944 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
946 // Verify the student cannot make changes to the submission.
947 $output = $assign->view_student_summary($this->students[0], true);
948 $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
950 // Mark the submission.
951 $this->setUser($this->teachers[0]);
952 $data = new stdClass();
953 $data->grade = '50.0';
954 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
956 // Check the student can see the grade.
957 $this->setUser($this->students[0]);
958 $output = $assign->view_student_summary($this->students[0], true);
959 $this->assertNotEquals(false, strpos($output, '50.0'));
961 // Allow the student another attempt.
962 $this->teachers[0]->ignoresesskey = true;
963 $this->setUser($this->teachers[0]);
964 $result = $assign->testable_process_add_attempt($this->students[0]->id);
965 $this->assertEquals(true, $result);
967 // Check that the previous attempt is now in the submission history table.
968 $this->setUser($this->students[0]);
969 $output = $assign->view_student_summary($this->students[0], true);
970 // Need a better check.
971 $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
973 // Check that the student now has a button for Add a new attempt".
974 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
975 // Check that the student now does not have a button for Submit.
976 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
978 // Check that the student now has a submission history.
979 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
981 $this->setUser($this->teachers[0]);
982 // Check that the grading table loads correctly and contains this user.
983 // This is also testing that we do not get duplicate rows in the grading table.
984 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
985 $output = $assign->get_renderer()->render($gradingtable);
986 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
988 // Should be 1 not 2.
989 $this->assertEquals(1, $assign->count_submissions());
990 $this->assertEquals(1, $assign->count_submissions_with_status('reopened'));
991 $this->assertEquals(0, $assign->count_submissions_need_grading());
992 $this->assertEquals(1, $assign->count_grades());
994 // Change max attempts to unlimited.
995 $formdata = clone($assign->get_instance());
996 $formdata->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS;
997 $formdata->instance = $formdata->id;
998 $assign->update_instance($formdata);
1000 // Check we can repopen still.
1001 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1002 $this->assertEquals(true, $result);
1004 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
1005 $this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
1009 public function test_markingworkflow() {
1012 $this->setUser($this->editingteachers[0]);
1013 $assign = $this->create_instance(array('markingworkflow'=>1));
1014 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1016 // Mark the submission and set to notmarked.
1017 $this->setUser($this->teachers[0]);
1018 $data = new stdClass();
1019 $data->grade = '50.0';
1020 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
1021 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1023 // Check the student can't see the grade.
1024 $this->setUser($this->students[0]);
1025 $output = $assign->view_student_summary($this->students[0], true);
1026 $this->assertEquals(false, strpos($output, '50.0'));
1028 // Mark the submission and set to inmarking.
1029 $this->setUser($this->teachers[0]);
1030 $data = new stdClass();
1031 $data->grade = '50.0';
1032 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
1033 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1035 // Check the student can't see the grade.
1036 $this->setUser($this->students[0]);
1037 $output = $assign->view_student_summary($this->students[0], true);
1038 $this->assertEquals(false, strpos($output, '50.0'));
1040 // Mark the submission and set to readyforreview.
1041 $this->setUser($this->teachers[0]);
1042 $data = new stdClass();
1043 $data->grade = '50.0';
1044 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
1045 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1047 // Check the student can't see the grade.
1048 $this->setUser($this->students[0]);
1049 $output = $assign->view_student_summary($this->students[0], true);
1050 $this->assertEquals(false, strpos($output, '50.0'));
1052 // Mark the submission and set to inreview.
1053 $this->setUser($this->teachers[0]);
1054 $data = new stdClass();
1055 $data->grade = '50.0';
1056 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
1057 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1059 // Check the student can't see the grade.
1060 $this->setUser($this->students[0]);
1061 $output = $assign->view_student_summary($this->students[0], true);
1062 $this->assertEquals(false, strpos($output, '50.0'));
1064 // Mark the submission and set to readyforrelease.
1065 $this->setUser($this->teachers[0]);
1066 $data = new stdClass();
1067 $data->grade = '50.0';
1068 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
1069 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1071 // Check the student can't see the grade.
1072 $this->setUser($this->students[0]);
1073 $output = $assign->view_student_summary($this->students[0], true);
1074 $this->assertEquals(false, strpos($output, '50.0'));
1076 // Mark the submission and set to released.
1077 $this->setUser($this->teachers[0]);
1078 $data = new stdClass();
1079 $data->grade = '50.0';
1080 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
1081 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1083 // Check the student can see the grade.
1084 $this->setUser($this->students[0]);
1085 $output = $assign->view_student_summary($this->students[0], true);
1086 $this->assertNotEquals(false, strpos($output, '50.0'));
1089 public function test_markerallocation() {
1092 $this->setUser($this->editingteachers[0]);
1093 $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
1094 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1096 // Allocate marker to submission.
1097 $data = new stdClass();
1098 $data->allocatedmarker = $this->teachers[0]->id;
1099 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1101 // Check the allocated marker can view the submission.
1102 $this->setUser($this->teachers[0]);
1103 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1104 $output = $assign->get_renderer()->render($gradingtable);
1105 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1107 // Check that other teachers can't view this submission.
1108 $this->setUser($this->teachers[1]);
1109 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1110 $output = $assign->get_renderer()->render($gradingtable);
1111 $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
1114 public function test_extension_granted_event() {
1115 $this->setUser($this->editingteachers[0]);
1117 $tomorrow = time() + 24*60*60;
1118 $yesterday = time() - 24*60*60;
1120 $assign = $this->create_instance(array('duedate' => $yesterday, 'cutoffdate' => $yesterday));
1121 $sink = $this->redirectEvents();
1123 $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
1125 $events = $sink->get_events();
1126 $this->assertCount(1, $events);
1127 $event = reset($events);
1128 $this->assertInstanceOf('\mod_assign\event\extension_granted', $event);
1129 $this->assertEquals($assign->get_context(), $event->get_context());
1130 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1131 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1133 $assign->get_course()->id,
1136 'view.php?id=' . $assign->get_course_module()->id,
1137 $this->students[0]->id,
1138 $assign->get_course_module()->id,
1139 $this->editingteachers[0]->id
1141 $this->assertEventLegacyLogData($expected, $event);
1145 public function test_submission_locked_event() {
1146 $this->editingteachers[0]->ignoresesskey = true;
1147 $this->setUser($this->editingteachers[0]);
1149 $assign = $this->create_instance();
1150 $sink = $this->redirectEvents();
1152 $assign->lock_submission($this->students[0]->id);
1154 $events = $sink->get_events();
1155 $this->assertCount(1, $events);
1156 $event = reset($events);
1157 $this->assertInstanceOf('\mod_assign\event\submission_locked', $event);
1158 $this->assertEquals($assign->get_context(), $event->get_context());
1159 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1160 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1162 $assign->get_course()->id,
1165 'view.php?id=' . $assign->get_course_module()->id,
1166 get_string('locksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
1167 'fullname' => fullname($this->students[0]))),
1168 $assign->get_course_module()->id,
1169 $this->editingteachers[0]->id
1171 $this->assertEventLegacyLogData($expected, $event);
1174 // Revert to defaults.
1175 $this->editingteachers[0]->ignoresesskey = false;
1178 public function test_identities_revealed_event() {
1179 $this->editingteachers[0]->ignoresesskey = true;
1180 $this->setUser($this->editingteachers[0]);
1182 $assign = $this->create_instance(array('blindmarking'=>1));
1183 $sink = $this->redirectEvents();
1185 $assign->reveal_identities();
1187 $events = $sink->get_events();
1188 $this->assertCount(1, $events);
1189 $event = reset($events);
1190 $this->assertInstanceOf('\mod_assign\event\identities_revealed', $event);
1191 $this->assertEquals($assign->get_context(), $event->get_context());
1192 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1194 $assign->get_course()->id,
1196 'reveal identities',
1197 'view.php?id=' . $assign->get_course_module()->id,
1198 get_string('revealidentities', 'assign'),
1199 $assign->get_course_module()->id,
1200 $this->editingteachers[0]->id
1202 $this->assertEventLegacyLogData($expected, $event);
1205 // Revert to defaults.
1206 $this->editingteachers[0]->ignoresesskey = false;
1209 public function test_submission_status_updated_event() {
1210 $this->editingteachers[0]->ignoresesskey = true;
1211 $this->setUser($this->editingteachers[0]);
1213 $assign = $this->create_instance();
1214 $submission = $assign->get_user_submission($this->students[0]->id, true);
1215 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1216 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1218 $sink = $this->redirectEvents();
1219 $assign->revert_to_draft($this->students[0]->id);
1221 $events = $sink->get_events();
1222 $this->assertCount(1, $events);
1223 $event = reset($events);
1224 $this->assertInstanceOf('\mod_assign\event\submission_status_updated', $event);
1225 $this->assertEquals($assign->get_context(), $event->get_context());
1226 $this->assertEquals($submission->id, $event->objectid);
1227 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1228 $this->assertEquals(ASSIGN_SUBMISSION_STATUS_DRAFT, $event->other['newstatus']);
1230 $assign->get_course()->id,
1232 'revert submission to draft',
1233 'view.php?id=' . $assign->get_course_module()->id,
1234 get_string('reverttodraftforstudent', 'assign', array('id' => $this->students[0]->id,
1235 'fullname' => fullname($this->students[0]))),
1236 $assign->get_course_module()->id,
1237 $this->editingteachers[0]->id
1239 $this->assertEventLegacyLogData($expected, $event);
1242 // Revert to defaults.
1243 $this->editingteachers[0]->ignoresesskey = false;
1246 public function test_marker_updated_event() {
1247 $this->editingteachers[0]->ignoresesskey = true;
1248 $this->setUser($this->editingteachers[0]);
1250 $assign = $this->create_instance();
1252 $sink = $this->redirectEvents();
1253 $assign->testable_process_set_batch_marking_allocation($this->students[0]->id, $this->teachers[0]->id);
1255 $events = $sink->get_events();
1256 $this->assertCount(1, $events);
1257 $event = reset($events);
1258 $this->assertInstanceOf('\mod_assign\event\marker_updated', $event);
1259 $this->assertEquals($assign->get_context(), $event->get_context());
1260 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1261 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1262 $this->assertEquals($this->editingteachers[0]->id, $event->userid);
1263 $this->assertEquals($this->teachers[0]->id, $event->other['markerid']);
1265 $assign->get_course()->id,
1267 'set marking allocation',
1268 'view.php?id=' . $assign->get_course_module()->id,
1269 get_string('setmarkerallocationforlog', 'assign', array('id' => $this->students[0]->id,
1270 'fullname' => fullname($this->students[0]), 'marker' => fullname($this->teachers[0]))),
1271 $assign->get_course_module()->id,
1272 $this->editingteachers[0]->id
1274 $this->assertEventLegacyLogData($expected, $event);
1277 // Revert to defaults.
1278 $this->editingteachers[0]->ignoresesskey = false;
1281 public function test_workflow_state_updated_event() {
1282 $this->editingteachers[0]->ignoresesskey = true;
1283 $this->setUser($this->editingteachers[0]);
1285 $assign = $this->create_instance();
1287 $sink = $this->redirectEvents();
1288 $assign->testable_process_set_batch_marking_workflow_state($this->students[0]->id, ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW);
1290 $events = $sink->get_events();
1291 $this->assertCount(1, $events);
1292 $event = reset($events);
1293 $this->assertInstanceOf('\mod_assign\event\workflow_state_updated', $event);
1294 $this->assertEquals($assign->get_context(), $event->get_context());
1295 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1296 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1297 $this->assertEquals($this->editingteachers[0]->id, $event->userid);
1298 $this->assertEquals(ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW, $event->other['newstate']);
1300 $assign->get_course()->id,
1302 'set marking workflow state',
1303 'view.php?id=' . $assign->get_course_module()->id,
1304 get_string('setmarkingworkflowstateforlog', 'assign', array('id' => $this->students[0]->id,
1305 'fullname' => fullname($this->students[0]), 'state' => ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW)),
1306 $assign->get_course_module()->id,
1307 $this->editingteachers[0]->id
1309 $this->assertEventLegacyLogData($expected, $event);
1312 // Revert to defaults.
1313 $this->editingteachers[0]->ignoresesskey = false;
1316 public function test_submission_duplicated_event() {
1317 $this->setUser($this->students[0]);
1319 $assign = $this->create_instance();
1320 $submission1 = $assign->get_user_submission($this->students[0]->id, true, 0);
1321 $submission2 = $assign->get_user_submission($this->students[0]->id, true, 1);
1322 $submission2->status = ASSIGN_SUBMISSION_STATUS_REOPENED;
1323 $assign->testable_update_submission($submission2, $this->students[0]->id, time(), $assign->get_instance()->teamsubmission);
1325 $sink = $this->redirectEvents();
1327 $assign->copy_previous_attempt($notices);
1329 $events = $sink->get_events();
1330 $this->assertCount(1, $events);
1331 $event = reset($events);
1332 $this->assertInstanceOf('\mod_assign\event\submission_duplicated', $event);
1333 $this->assertEquals($assign->get_context(), $event->get_context());
1334 $this->assertEquals($submission2->id, $event->objectid);
1335 $this->assertEquals($this->students[0]->id, $event->userid);
1336 $submission2->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
1338 $assign->get_course()->id,
1341 'view.php?id=' . $assign->get_course_module()->id,
1342 $assign->testable_format_submission_for_log($submission2),
1343 $assign->get_course_module()->id,
1344 $this->students[0]->id
1346 $this->assertEventLegacyLogData($expected, $event);
1350 public function test_submission_unlocked_event() {
1351 $this->editingteachers[0]->ignoresesskey = true;
1352 $this->setUser($this->editingteachers[0]);
1354 $assign = $this->create_instance();
1355 $sink = $this->redirectEvents();
1357 $assign->unlock_submission($this->students[0]->id);
1359 $events = $sink->get_events();
1360 $this->assertCount(1, $events);
1361 $event = reset($events);
1362 $this->assertInstanceOf('\mod_assign\event\submission_unlocked', $event);
1363 $this->assertEquals($assign->get_context(), $event->get_context());
1364 $this->assertEquals($assign->get_instance()->id, $event->objectid);
1365 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1367 $assign->get_course()->id,
1369 'unlock submission',
1370 'view.php?id=' . $assign->get_course_module()->id,
1371 get_string('unlocksubmissionforstudent', 'assign', array('id' => $this->students[0]->id,
1372 'fullname' => fullname($this->students[0]))),
1373 $assign->get_course_module()->id,
1374 $this->editingteachers[0]->id
1376 $this->assertEventLegacyLogData($expected, $event);
1379 // Revert to defaults.
1380 $this->editingteachers[0]->ignoresesskey = false;
1383 public function test_submission_graded_event() {
1384 $this->setUser($this->editingteachers[0]);
1385 $assign = $this->create_instance();
1387 // Test apply_grade_to_user.
1388 $sink = $this->redirectEvents();
1390 $data = new stdClass();
1391 $data->grade = '50.0';
1392 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1393 $grade = $assign->get_user_grade($this->students[0]->id, false, 0);
1395 $events = $sink->get_events();
1396 $this->assertCount(1, $events);
1397 $event = reset($events);
1398 $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
1399 $this->assertEquals($assign->get_context(), $event->get_context());
1400 $this->assertEquals($grade->id, $event->objectid);
1401 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1403 $assign->get_course()->id,
1406 'view.php?id=' . $assign->get_course_module()->id,
1407 $assign->format_grade_for_log($grade),
1408 $assign->get_course_module()->id,
1409 $this->editingteachers[0]->id
1411 $this->assertEventLegacyLogData($expected, $event);
1414 // Test process_save_quick_grades.
1415 $sink = $this->redirectEvents();
1418 'grademodified_' . $this->students[0]->id => time(),
1419 'quickgrade_' . $this->students[0]->id => '60.0'
1421 $assign->testable_process_save_quick_grades($data);
1422 $grade = $assign->get_user_grade($this->students[0]->id, false);
1423 $this->assertEquals('60.0', $grade->grade);
1425 $events = $sink->get_events();
1426 $this->assertCount(1, $events);
1427 $event = reset($events);
1428 $this->assertInstanceOf('\mod_assign\event\submission_graded', $event);
1429 $this->assertEquals($assign->get_context(), $event->get_context());
1430 $this->assertEquals($grade->id, $event->objectid);
1431 $this->assertEquals($this->students[0]->id, $event->relateduserid);
1433 $assign->get_course()->id,
1436 'view.php?id=' . $assign->get_course_module()->id,
1437 $assign->format_grade_for_log($grade),
1438 $assign->get_course_module()->id,
1439 $this->editingteachers[0]->id
1441 $this->assertEventLegacyLogData($expected, $event);
1445 public function test_disable_submit_after_cutoff_date() {
1448 $this->setUser($this->editingteachers[0]);
1450 $tomorrow = $now + 24*60*60;
1451 $lastweek = $now - 7*24*60*60;
1452 $yesterday = $now - 24*60*60;
1454 $assign = $this->create_instance(array('duedate'=>$yesterday,
1455 'cutoffdate'=>$tomorrow,
1456 'assignsubmission_onlinetext_enabled'=>1));
1457 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1459 // Student should be able to see an add submission button.
1460 $this->setUser($this->students[0]);
1461 $output = $assign->view_student_summary($this->students[0], true);
1462 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1464 // Add a submission but don't submit now.
1465 $submission = $assign->get_user_submission($this->students[0]->id, true);
1466 $data = new stdClass();
1467 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1468 'text'=>'Submission text',
1469 'format'=>FORMAT_MOODLE);
1470 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1471 $plugin->save($submission, $data);
1473 // Create another instance with cut-off and due-date already passed.
1474 $this->setUser($this->editingteachers[0]);
1476 $assign = $this->create_instance(array('duedate'=>$lastweek,
1477 'cutoffdate'=>$yesterday,
1478 'assignsubmission_onlinetext_enabled'=>1));
1480 $this->setUser($this->students[0]);
1481 $output = $assign->view_student_summary($this->students[0], true);
1482 $this->assertNotContains($output, get_string('editsubmission', 'assign'),
1483 'Should not be able to edit after cutoff date.');
1484 $this->assertNotContains($output, get_string('submitassignment', 'assign'),
1485 'Should not be able to submit after cutoff date.');
1488 * Testing for submission comment plugin settings
1490 public function test_submission_comment_plugin_settings() {
1493 $commentconfig = false;
1494 if (!empty($CFG->usecomments)) {
1495 $commentconfig = $CFG->usecomments;
1498 $CFG->usecomments = true;
1499 $assign = $this->create_instance();
1500 $plugin = $assign->get_submission_plugin_by_type('comments');
1501 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1503 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
1504 $plugin = $assign->get_submission_plugin_by_type('comments');
1505 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1507 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
1508 $plugin = $assign->get_submission_plugin_by_type('comments');
1509 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1511 $CFG->usecomments = false;
1512 $assign = $this->create_instance();
1513 $plugin = $assign->get_submission_plugin_by_type('comments');
1514 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1516 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
1517 $plugin = $assign->get_submission_plugin_by_type('comments');
1518 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1520 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
1521 $plugin = $assign->get_submission_plugin_by_type('comments');
1522 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1524 $CFG->usecomments = $commentconfig;
1528 * Testing for comment inline settings
1530 public function test_feedback_comment_commentinline() {
1533 $sourcetext = "Hello!
1535 I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
1537 URL outside a tag: https://moodle.org/logo/logo-240x60.gif
1538 Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
1540 External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/>
1541 External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\"/>
1542 Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/>
1543 Internal link 2:<img alt=\"Moodle\" src=\"@@PLUGINFILE@@logo-240x60.gif\"/>
1544 Anchor link 1:<a href=\"@@PLUGINFILE@@logo-240x60.gif\" alt=\"bananas\">Link text</a>
1545 Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
1548 // Note the internal images have been stripped and the html is purified (quotes fixed in this case).
1549 $filteredtext = "Hello!
1551 I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
1553 URL outside a tag: https://moodle.org/logo/logo-240x60.gif
1554 Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
1556 External link 1:<img src=\"https://moodle.org/logo/logo-240x60.gif\" alt=\"Moodle\" />
1557 External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\" />
1560 Anchor link 1:Link text
1561 Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
1564 $this->setUser($this->editingteachers[0]);
1565 $params = array('assignsubmission_onlinetext_enabled' => 1,
1566 'assignfeedback_comments_enabled' => 1,
1567 'assignfeedback_comments_commentinline' => 1);
1568 $assign = $this->create_instance($params);
1570 $this->setUser($this->students[0]);
1571 // Add a submission but don't submit now.
1572 $submission = $assign->get_user_submission($this->students[0]->id, true);
1573 $data = new stdClass();
1575 // Test the internal link is stripped, but the external one is not.
1576 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1577 'text'=>$sourcetext,
1578 'format'=>FORMAT_MOODLE);
1580 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1581 $plugin->save($submission, $data);
1583 $this->setUser($this->editingteachers[0]);
1585 $data = new stdClass();
1586 require_once($CFG->dirroot . '/mod/assign/gradeform.php');
1587 $pagination = array('userid'=>$this->students[0]->id,
1590 'useridlistid'=>time(),
1591 'attemptnumber'=>0);
1592 $formparams = array($assign, $data, $pagination);
1593 $mform = new mod_assign_grade_form(null, $formparams);
1595 $this->assertEquals($filteredtext, $data->assignfeedbackcomments_editor['text']);
1599 * Testing for feedback comment plugin settings
1601 public function test_feedback_plugin_settings() {
1603 $assign = $this->create_instance();
1604 $plugin = $assign->get_feedback_plugin_by_type('comments');
1605 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1607 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 0));
1608 $plugin = $assign->get_feedback_plugin_by_type('comments');
1609 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1611 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
1612 $plugin = $assign->get_feedback_plugin_by_type('comments');
1613 $this->assertEquals(1, $plugin->is_enabled('enabled'));