weekly release 2.9dev
[moodle.git] / mod / assign / tests / locallib_test.php
CommitLineData
47f48152
DW
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/>.
16
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 */
25
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30require_once($CFG->dirroot . '/mod/assign/locallib.php');
31require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
9c986ee0 32require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
47f48152
DW
33
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 */
9c986ee0 40class mod_assign_locallib_testcase extends mod_assign_base_testcase {
47f48152
DW
41
42 public function test_return_links() {
c2114099 43 global $PAGE;
47f48152
DW
44 $this->setUser($this->editingteachers[0]);
45 $returnaction = 'RETURNACTION';
c2114099 46 $returnparams = array('param'=>'1');
47f48152 47 $assign = $this->create_instance();
c2114099 48 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
47f48152
DW
49 $assign->register_return_link($returnaction, $returnparams);
50 $this->assertEquals($returnaction, $assign->get_return_action());
51 $this->assertEquals($returnparams, $assign->get_return_params());
52 }
53
54 public function test_get_feedback_plugins() {
55 $this->setUser($this->editingteachers[0]);
56 $assign = $this->create_instance();
bd3b3bba 57 $installedplugins = array_keys(core_component::get_plugin_list('assignfeedback'));
11527706
DW
58
59 foreach ($assign->get_feedback_plugins() as $plugin) {
60 $this->assertContains($plugin->get_type(), $installedplugins, 'Feedback plugin not in list of installed plugins');
61 }
47f48152
DW
62 }
63
64 public function test_get_submission_plugins() {
65 $this->setUser($this->editingteachers[0]);
66 $assign = $this->create_instance();
bd3b3bba 67 $installedplugins = array_keys(core_component::get_plugin_list('assignsubmission'));
11527706
DW
68
69 foreach ($assign->get_submission_plugins() as $plugin) {
70 $this->assertContains($plugin->get_type(), $installedplugins, 'Submission plugin not in list of installed plugins');
71 }
47f48152
DW
72 }
73
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());
78
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')));
83
84 // Test students cannot reveal identities.
85 $nopermission = false;
05a6445a 86 $this->students[0]->ignoresesskey = true;
47f48152
DW
87 $this->setUser($this->students[0]);
88 $this->setExpectedException('required_capability_exception');
05a6445a
DW
89 $assign->reveal_identities();
90 $this->students[0]->ignoresesskey = false;
47f48152
DW
91
92 // Test teachers cannot reveal identities.
93 $nopermission = false;
05a6445a 94 $this->teachers[0]->ignoresesskey = true;
47f48152
DW
95 $this->setUser($this->teachers[0]);
96 $this->setExpectedException('required_capability_exception');
05a6445a
DW
97 $assign->reveal_identities();
98 $this->teachers[0]->ignoresesskey = false;
47f48152
DW
99
100 // Test sesskey is required.
47f48152
DW
101 $this->setUser($this->editingteachers[0]);
102 $this->setExpectedException('moodle_exception');
05a6445a 103 $assign->reveal_identities();
47f48152
DW
104
105 // Test editingteacher can reveal identities if sesskey is ignored.
106 $this->editingteachers[0]->ignoresesskey = true;
107 $this->setUser($this->editingteachers[0]);
05a6445a 108 $assign->reveal_identities();
47f48152 109 $this->assertEquals(false, $assign->is_blind_marking());
05a6445a 110 $this->editingteachers[0]->ignoresesskey = false;
47f48152
DW
111
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')));
116
117 // Set this back to default.
118 $this->editingteachers[0]->ignoresesskey = false;
119 }
120
79397b56
DB
121 /**
122 * Test submissions with extension date.
123 */
124 public function test_gradingtable_extension_due_date() {
125 global $PAGE;
126
127 // Setup the assignment.
128 $this->create_extra_users();
129 $this->setUser($this->editingteachers[0]);
130 $assign = $this->create_instance(array(
131 'assignsubmission_onlinetext_enabled'=>1,
132 'duedate' => time() - 4 * 24 * 60 * 60,
133 ));
134 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
135 'id' => $assign->get_course_module()->id,
136 'action' => 'grading',
137 )));
138
139 // Check that the assignment is late.
140 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
141 $output = $assign->get_renderer()->render($gradingtable);
142 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
143 $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60)), $output);
144
145 // Grant an extension.
5b460d65
MG
146 $extendedtime = time() + 2 * 24 * 60 * 60;
147 $assign->testable_save_user_extension($this->students[0]->id, $extendedtime);
79397b56
DB
148 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
149 $output = $assign->get_renderer()->render($gradingtable);
150 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
5b460d65 151 $this->assertContains(get_string('userextensiondate', 'assign', userdate($extendedtime)), $output);
79397b56
DB
152
153 // Simulate a submission.
154 $this->setUser($this->students[0]);
155 $submission = $assign->get_user_submission($this->students[0]->id, true);
156 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
157 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
158 $data = new stdClass();
159 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
160 'text'=>'Submission text',
161 'format'=>FORMAT_MOODLE);
162 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
163 $plugin->save($submission, $data);
164
165 // Verify output.
166 $this->setUser($this->editingteachers[0]);
167 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
168 $output = $assign->get_renderer()->render($gradingtable);
169 $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
5b460d65 170 $this->assertContains(get_string('userextensiondate', 'assign', userdate($extendedtime)), $output);
79397b56
DB
171 }
172
173 /**
174 * Test that late submissions with extension date calculate correctly.
175 */
176 public function test_gradingtable_extension_date_calculation_for_lateness() {
177 global $PAGE;
178
179 // Setup the assignment.
180 $this->create_extra_users();
181 $this->setUser($this->editingteachers[0]);
a0f8db77 182 $time = time();
79397b56
DB
183 $assign = $this->create_instance(array(
184 'assignsubmission_onlinetext_enabled'=>1,
a0f8db77 185 'duedate' => $time - 4 * 24 * 60 * 60,
79397b56
DB
186 ));
187 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
188 'id' => $assign->get_course_module()->id,
189 'action' => 'grading',
190 )));
191
192 // Check that the assignment is late.
193 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
194 $output = $assign->get_renderer()->render($gradingtable);
195 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
a0f8db77
DW
196 $difftime = time() - $time;
197 $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60 + $difftime)), $output);
79397b56
DB
198
199 // Grant an extension that is in the past.
a0f8db77 200 $assign->testable_save_user_extension($this->students[0]->id, $time - 2 * 24 * 60 * 60);
79397b56
DB
201 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
202 $output = $assign->get_renderer()->render($gradingtable);
203 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
a0f8db77
DW
204 $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
205 $difftime = time() - $time;
206 $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
207
208 // Simulate a submission.
209 $this->setUser($this->students[0]);
210 $submission = $assign->get_user_submission($this->students[0]->id, true);
211 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
212 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
213 $data = new stdClass();
214 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
215 'text'=>'Submission text',
216 'format'=>FORMAT_MOODLE);
217 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
218 $plugin->save($submission, $data);
a0f8db77 219 $submittedtime = time();
79397b56
DB
220
221 // Verify output.
222 $this->setUser($this->editingteachers[0]);
223 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
224 $output = $assign->get_renderer()->render($gradingtable);
225 $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
a0f8db77
DW
226 $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
227
228 $difftime = $submittedtime - $time;
229 $this->assertContains(get_string('submittedlateshort', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
230 }
231
232 /**
233 * Check that group submission information is rendered correctly in the
234 * grading table.
235 */
236 public function test_gradingtable_group_submissions_rendering() {
237 global $PAGE;
238
239 $this->create_extra_users();
240 // Now verify group assignments.
241 $this->setUser($this->teachers[0]);
242 $assign = $this->create_instance(array(
243 'teamsubmission' => 1,
244 'assignsubmission_onlinetext_enabled' => 1,
245 'submissiondrafts' => 1,
246 'requireallteammemberssubmit' => 0,
247 ));
248 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
249 'id' => $assign->get_course_module()->id,
250 'action' => 'grading',
251 )));
252
253 // Add a submission.
254 $this->setUser($this->extrastudents[0]);
255 $data = new stdClass();
256 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
257 'text'=>'Submission text',
258 'format'=>FORMAT_MOODLE);
259 $notices = array();
260 $assign->save_submission($data, $notices);
261
262 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
263 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
264 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
265
266 // Check output.
267 $this->setUser($this->teachers[0]);
268 $gradingtable = new assign_grading_table($assign, 4, '', 0, true);
269 $output = $assign->get_renderer()->render($gradingtable);
270 $document = new DOMDocument();
271 $document->loadHTML($output);
272 $xpath = new DOMXPath($document);
273
274 // Check status.
275 $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c4"]/div[@class="submissionstatussubmitted"])'));
276 $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c4"]/div[@class="submissionstatussubmitted"])'));
277
278 // Check submission last modified date
279 $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c8"])')));
280 $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c8"])')));
281
282 // Check group.
283 $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c5"])'));
284 $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c5"])'));
285
286 // Check submission text.
287 $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c9"]/div/div)'));
288 $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c9"]/div/div)'));
289
290 // Check comments can be made.
291 $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r0_c10"]//textarea)'));
292 $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r3_c10"]//textarea)'));
293 }
294
47f48152
DW
295 public function test_show_intro() {
296 // Test whether we are showing the intro at the correct times.
297 $this->setUser($this->editingteachers[0]);
298 $assign = $this->create_instance(array('alwaysshowdescription'=>1));
299
300 $this->assertEquals(true, $assign->testable_show_intro());
301
302 $tomorrow = time() + (24*60*60);
303
304 $assign = $this->create_instance(array('alwaysshowdescription'=>0,
305 'allowsubmissionsfromdate'=>$tomorrow));
306 $this->assertEquals(false, $assign->testable_show_intro());
307 $yesterday = time() - (24*60*60);
308 $assign = $this->create_instance(array('alwaysshowdescription'=>0,
309 'allowsubmissionsfromdate'=>$yesterday));
310 $this->assertEquals(true, $assign->testable_show_intro());
311 }
312
313 public function test_has_submissions_or_grades() {
314 $this->setUser($this->editingteachers[0]);
315 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
316
317 $instance = $assign->get_instance();
318
319 // Should start empty.
320 $this->assertEquals(false, $assign->has_submissions_or_grades());
321
322 // Simulate a submission.
323 $this->setUser($this->students[0]);
324 $submission = $assign->get_user_submission($this->students[0]->id, true);
325 $data = new stdClass();
326 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
327 'text'=>'Submission text',
328 'format'=>FORMAT_MOODLE);
329 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
330 $plugin->save($submission, $data);
331
332 // Now test again.
333 $this->assertEquals(true, $assign->has_submissions_or_grades());
334 // Set this back to default.
335 $this->students[0]->ignoresesskey = false;
336 }
337
338 public function test_delete_grades() {
339 $this->setUser($this->editingteachers[0]);
340 $assign = $this->create_instance();
341
342 // Simulate adding a grade.
343 $this->setUser($this->teachers[0]);
344 $data = new stdClass();
345 $data->grade = '50.0';
df211804 346 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
347
348 // Now see if the data is in the gradebook.
349 $gradinginfo = grade_get_grades($this->course->id,
350 'mod',
351 'assign',
352 $assign->get_instance()->id);
353
354 $this->assertNotEquals(0, count($gradinginfo->items));
355
356 $assign->testable_delete_grades();
357 $gradinginfo = grade_get_grades($this->course->id,
358 'mod',
359 'assign',
360 $assign->get_instance()->id);
361
362 $this->assertEquals(0, count($gradinginfo->items));
363 }
364
365 public function test_delete_instance() {
366 $this->setUser($this->editingteachers[0]);
367 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
368
369 // Simulate adding a grade.
370 $this->setUser($this->teachers[0]);
371 $data = new stdClass();
372 $data->grade = '50.0';
df211804 373 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
374
375 // Simulate a submission.
376 $this->setUser($this->students[0]);
377 $submission = $assign->get_user_submission($this->students[0]->id, true);
378 $data = new stdClass();
379 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
380 'text'=>'Submission text',
381 'format'=>FORMAT_MOODLE);
382 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
383 $plugin->save($submission, $data);
384
385 // Now try and delete.
386 $this->assertEquals(true, $assign->delete_instance());
387 }
388
389 public function test_reset_userdata() {
390 global $DB;
391
392 $now = time();
393 $this->setUser($this->editingteachers[0]);
394 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
395 'duedate'=>$now));
396
397 // Simulate adding a grade.
398 $this->setUser($this->teachers[0]);
399 $data = new stdClass();
400 $data->grade = '50.0';
df211804 401 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
402
403 // Simulate a submission.
404 $this->setUser($this->students[0]);
405 $submission = $assign->get_user_submission($this->students[0]->id, true);
406 $data = new stdClass();
407 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
408 'text'=>'Submission text',
409 'format'=>FORMAT_MOODLE);
410 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
411 $plugin->save($submission, $data);
412
413 $this->assertEquals(true, $assign->has_submissions_or_grades());
414 // Now try and reset.
415 $data = new stdClass();
416 $data->reset_assign_submissions = 1;
417 $data->reset_gradebook_grades = 1;
418 $data->courseid = $this->course->id;
419 $data->timeshift = 24*60*60;
420 $this->setUser($this->editingteachers[0]);
421 $assign->reset_userdata($data);
422 $this->assertEquals(false, $assign->has_submissions_or_grades());
423
424 // Reload the instance data.
425 $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
426 $this->assertEquals($now + 24*60*60, $instance->duedate);
e63515ba
RT
427
428 // Test reset using assign_reset_userdata().
429 $assignduedate = $instance->duedate; // Keep old updated value for comparison.
430 $data->timeshift = 2*24*60*60;
431 assign_reset_userdata($data);
432 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
433 $this->assertEquals($assignduedate + 2*24*60*60, $instance->duedate);
434
435 // Create one more assignment and reset, make sure time shifted for previous assignment is not changed.
436 $assign2 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
437 'duedate' => $now));
438 $assignduedate = $instance->duedate;
439 $data->timeshift = 3*24*60*60;
440 $assign2->reset_userdata($data);
441 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
442 $this->assertEquals($assignduedate, $instance->duedate);
443 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
444 $this->assertEquals($now + 3*24*60*60, $instance2->duedate);
445
446 // Reset both assignments using assign_reset_userdata() and make sure both assignments have same date.
447 $assignduedate = $instance->duedate;
448 $assign2duedate = $instance2->duedate;
449 $data->timeshift = 4*24*60*60;
450 assign_reset_userdata($data);
451 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
452 $this->assertEquals($assignduedate + 4*24*60*60, $instance->duedate);
453 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
454 $this->assertEquals($assign2duedate + 4*24*60*60, $instance2->duedate);
47f48152
DW
455 }
456
457 public function test_plugin_settings() {
458 global $DB;
459
460 $now = time();
461 $this->setUser($this->editingteachers[0]);
462 $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
463 'assignsubmission_file_maxfiles'=>12,
464 'assignsubmission_file_maxsizebytes'=>10));
465
466 $plugin = $assign->get_submission_plugin_by_type('file');
467 $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
468 }
469
470 public function test_update_calendar() {
471 global $DB;
472
47f48152 473 $this->setUser($this->editingteachers[0]);
f588ea50
FM
474 $userctx = context_user::instance($this->editingteachers[0]->id)->id;
475
476 // Hack to pretend that there was an editor involved. We need both $_POST and $_REQUEST, and a sesskey.
477 $draftid = file_get_unused_draft_itemid();
478 $_REQUEST['introeditor'] = $draftid;
479 $_POST['introeditor'] = $draftid;
480 $_POST['sesskey'] = sesskey();
481
482 // Write links to a draft area.
483 $fakearealink1 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">link</a>', 'draftfile.php', $userctx,
484 'user', 'draft', $draftid);
485 $fakearealink2 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">new</a>', 'draftfile.php', $userctx,
486 'user', 'draft', $draftid);
487
488 // Create a new assignment with links to a draft area.
489 $now = time();
490 $assign = $this->create_instance(array(
491 'duedate' => $now,
492 'intro' => $fakearealink1,
493 'introformat' => FORMAT_HTML
494 ));
47f48152
DW
495
496 // See if there is an event in the calendar.
497 $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
f588ea50
FM
498 $event = $DB->get_record('event', $params);
499 $this->assertNotEmpty($event);
500 $this->assertSame('link', $event->description); // The pluginfile links are removed.
47f48152 501
f588ea50
FM
502 // Make sure the same works when updating the assignment.
503 $instance = $assign->get_instance();
504 $instance->instance = $instance->id;
505 $instance->intro = $fakearealink2;
506 $instance->introformat = FORMAT_HTML;
507 $assign->update_instance($instance);
508 $params = array('modulename' => 'assign', 'instance' => $assign->get_instance()->id);
509 $event = $DB->get_record('event', $params);
510 $this->assertNotEmpty($event);
511 $this->assertSame('new', $event->description); // The pluginfile links are removed.
ae7638f7
DW
512
513 // Create an assignment with a description that should be hidden.
514 $assign = $this->create_instance(array('duedate'=>$now + 160,
515 'alwaysshowdescription'=>false,
8112670d 516 'allowsubmissionsfromdate'=>$now + 60,
ae7638f7
DW
517 'intro'=>'Some text'));
518
519 // Get the event from the calendar.
520 $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
521 $event = $DB->get_record('event', $params);
522
523 $this->assertEmpty($event->description);
8112670d
DW
524
525 // Change the allowsubmissionfromdate to the past - do this directly in the DB
526 // because if we call the assignment update method - it will update the calendar
527 // and we want to test that this works from cron.
528 $DB->set_field('assign', 'allowsubmissionsfromdate', $now - 60, array('id'=>$assign->get_instance()->id));
ae7638f7
DW
529 // Run cron to update the event in the calendar.
530 assign::cron();
531 $event = $DB->get_record('event', $params);
532
533 $this->assertContains('Some text', $event->description);
534
47f48152
DW
535 }
536
537 public function test_update_instance() {
538 global $DB;
539
540 $this->setUser($this->editingteachers[0]);
541 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
542
543 $now = time();
544 $instance = $assign->get_instance();
545 $instance->duedate = $now;
546 $instance->instance = $instance->id;
547 $instance->assignsubmission_onlinetext_enabled = 1;
47f48152
DW
548
549 $assign->update_instance($instance);
550
551 $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
552 $this->assertEquals($now, $instance->duedate);
553 }
554
8fd00a24
DW
555 public function test_cannot_submit_empty() {
556 global $PAGE;
557
558 $this->setUser($this->editingteachers[0]);
559 $assign = $this->create_instance(array('submissiondrafts'=>1));
560
561 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
562
563 // Test you cannot see the submit button for an offline assignment regardless.
564 $this->setUser($this->students[0]);
565 $output = $assign->view_student_summary($this->students[0], true);
566 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
567
568 // Test you cannot see the submit button for an online text assignment with no submission.
569 $this->setUser($this->editingteachers[0]);
570 $instance = $assign->get_instance();
571 $instance->instance = $instance->id;
572 $instance->assignsubmission_onlinetext_enabled = 1;
573
574 $assign->update_instance($instance);
575 $this->setUser($this->students[0]);
576 $output = $assign->view_student_summary($this->students[0], true);
577 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
578
579 // Simulate a submission.
580 $submission = $assign->get_user_submission($this->students[0]->id, true);
581 $data = new stdClass();
582 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
583 'text'=>'Submission text',
584 'format'=>FORMAT_MOODLE);
585 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
586 $plugin->save($submission, $data);
587 // Test you can see the submit button for an online text assignment with a submission.
588 $output = $assign->view_student_summary($this->students[0], true);
589 $this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
590 }
591
47f48152 592 public function test_list_participants() {
c13ac85d 593 global $CFG, $DB;
594
df211804 595 $this->create_extra_users();
47f48152
DW
596 $this->setUser($this->editingteachers[0]);
597 $assign = $this->create_instance(array('grade'=>100));
598
a5c793c3 599 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
e6cc5347
RT
600
601 // Teacher with user preference set should see suspended users as well.
602 set_user_preference('grade_report_showonlyactiveenrol', false);
603 $assign = $this->create_instance(array('grade'=>100));
604 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
605 count($assign->list_participants(null, true)));
606
1ecb8044 607 // Non-editing teacher should not see suspended users, even if user preference is set.
e6cc5347
RT
608 $this->setUser($this->teachers[0]);
609 set_user_preference('grade_report_showonlyactiveenrol', false);
610 $assign = $this->create_instance(array('grade'=>100));
611 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
c13ac85d 612
613 // Turn on availability and a group restriction, and check that it doesn't
614 // show users who aren't in the group.
615 $CFG->enableavailability = true;
616 $specialgroup = $this->getDataGenerator()->create_group(
617 array('courseid' => $this->course->id));
618 $assign = $this->create_instance(array('grade' => 100,
619 'availability' => json_encode(\core_availability\tree::get_root_json(
620 array(\availability_group\condition::get_json($specialgroup->id))))));
621 groups_add_member($specialgroup, $this->students[0]);
622 groups_add_member($specialgroup, $this->students[1]);
623 $this->assertEquals(2, count($assign->list_participants(null, true)));
47f48152
DW
624 }
625
626 public function test_count_teams() {
df211804 627 $this->create_extra_users();
47f48152
DW
628 $this->setUser($this->editingteachers[0]);
629 $assign = $this->create_instance(array('teamsubmission'=>1));
630
a5c793c3 631 $this->assertEquals(self::GROUP_COUNT + 1, $assign->count_teams());
47f48152
DW
632 }
633
e2d2d8a1
DW
634 public function test_submit_to_default_group() {
635 global $DB;
636
637 $this->preventResetByRollback();
638 $sink = $this->redirectMessages();
639
640 $this->setUser($this->editingteachers[0]);
641 $params = array('teamsubmission' => 1,
642 'assignsubmission_onlinetext_enabled' => 1,
643 'submissiondrafts'=>0);
644 $assign = $this->create_instance($params);
645
646 $newstudent = $this->getDataGenerator()->create_user();
647 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
648 $this->getDataGenerator()->enrol_user($newstudent->id,
649 $this->course->id,
650 $studentrole->id);
651 $this->setUser($newstudent);
652 $data = new stdClass();
653 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
654 'text'=>'Submission text',
655 'format'=>FORMAT_MOODLE);
656 $notices = array();
657
658 $group = $assign->get_submission_group($newstudent->id);
659 $this->assertFalse($group, 'New student is in default group');
660 $assign->save_submission($data, $notices);
661 $this->assertEmpty($notices, 'No errors on save submission');
662
663 $sink->close();
664 }
665
47f48152 666 public function test_count_submissions() {
df211804 667 $this->create_extra_users();
47f48152
DW
668 $this->setUser($this->editingteachers[0]);
669 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
670
671 // Simulate a submission.
a5c793c3
DW
672 $this->setUser($this->extrastudents[0]);
673 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
9e3eee67
DW
674 $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
675 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
676 // Leave this one as DRAFT.
677 $data = new stdClass();
678 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
679 'text'=>'Submission text',
680 'format'=>FORMAT_MOODLE);
681 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
682 $plugin->save($submission, $data);
683
684 // Simulate adding a grade.
685 $this->setUser($this->teachers[0]);
686 $data = new stdClass();
687 $data->grade = '50.0';
df211804 688 $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
47f48152
DW
689
690 // Simulate a submission.
a5c793c3
DW
691 $this->setUser($this->extrastudents[1]);
692 $submission = $assign->get_user_submission($this->extrastudents[1]->id, true);
47f48152 693 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
a5c793c3 694 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
47f48152
DW
695 $data = new stdClass();
696 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
697 'text'=>'Submission text',
698 'format'=>FORMAT_MOODLE);
699 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
700 $plugin->save($submission, $data);
701
702 // Simulate a submission.
a5c793c3
DW
703 $this->setUser($this->extrastudents[2]);
704 $submission = $assign->get_user_submission($this->extrastudents[2]->id, true);
47f48152 705 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
a5c793c3 706 $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
47f48152
DW
707 $data = new stdClass();
708 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
709 'text'=>'Submission text',
710 'format'=>FORMAT_MOODLE);
711 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
712 $plugin->save($submission, $data);
713
714 // Simulate a submission.
a5c793c3
DW
715 $this->setUser($this->extrastudents[3]);
716 $submission = $assign->get_user_submission($this->extrastudents[3]->id, true);
47f48152 717 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
a5c793c3 718 $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
47f48152
DW
719 $data = new stdClass();
720 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
721 'text'=>'Submission text',
722 'format'=>FORMAT_MOODLE);
723 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
724 $plugin->save($submission, $data);
725
e6cc5347
RT
726 // Simulate a submission for suspended user, this will never be counted.
727 $this->setUser($this->extrastudents[3]);
728 $submission = $assign->get_user_submission($this->extrasuspendedstudents[0]->id, true);
729 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
730 $assign->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
731 $data = new stdClass();
732 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
733 'text'=>'Submission text',
734 'format'=>FORMAT_MOODLE);
735 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
736 $plugin->save($submission, $data);
737
47f48152
DW
738 // Simulate adding a grade.
739 $this->setUser($this->teachers[0]);
740 $data = new stdClass();
741 $data->grade = '50.0';
df211804 742 $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
e6cc5347 743 $assign->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
47f48152
DW
744
745 $this->assertEquals(2, $assign->count_grades());
746 $this->assertEquals(4, $assign->count_submissions());
747 $this->assertEquals(2, $assign->count_submissions_need_grading());
748 $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
749 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
750 }
751
752 public function test_get_grading_userid_list() {
df211804 753 $this->create_extra_users();
47f48152
DW
754 $this->setUser($this->editingteachers[0]);
755 $assign = $this->create_instance();
756
757 $users = $assign->testable_get_grading_userid_list();
a5c793c3 758 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
e6cc5347
RT
759
760 $this->setUser($this->editingteachers[0]);
761 set_user_preference('grade_report_showonlyactiveenrol', false);
762 $assign = $this->create_instance();
763
764 $users = $assign->testable_get_grading_userid_list();
765 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
47f48152
DW
766 }
767
768 public function test_cron() {
769 // First run cron so there are no messages waiting to be sent (from other tests).
770 cron_setup_user();
771 assign::cron();
772
773 // Now create an assignment and add some feedback.
774 $this->setUser($this->editingteachers[0]);
8e1266bf 775 $assign = $this->create_instance(array('sendstudentnotifications'=>1));
47f48152
DW
776
777 // Simulate adding a grade.
778 $this->setUser($this->teachers[0]);
779 $data = new stdClass();
780 $data->grade = '50.0';
df211804 781 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
4d2bd673 782 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
47f48152 783
f7dc9871
DW
784 $data->sendstudentnotifications = false;
785 $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
786
47f48152
DW
787 // Now run cron and see that one message was sent.
788 $this->preventResetByRollback();
789 $sink = $this->redirectMessages();
790 cron_setup_user();
4d2bd673 791 $this->expectOutputRegex('/Done processing 2 assignment submissions/');
47f48152
DW
792 assign::cron();
793
794 $messages = $sink->get_messages();
f7dc9871 795 // The sent count should be 2, because the 3rd one was marked as do not send notifications.
4d2bd673 796 $this->assertEquals(2, count($messages));
47f48152
DW
797 $this->assertEquals(1, $messages[0]->notification);
798 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
799 }
800
801 public function test_is_graded() {
802 $this->setUser($this->editingteachers[0]);
803 $assign = $this->create_instance();
804
805 // Simulate adding a grade.
806 $this->setUser($this->teachers[0]);
807 $data = new stdClass();
808 $data->grade = '50.0';
df211804 809 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
810
811 $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
812 $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
813 }
814
4a47008c
DW
815 public function test_can_grade() {
816 global $DB;
817
818 $this->setUser($this->editingteachers[0]);
819 $assign = $this->create_instance();
820
821 $this->setUser($this->students[0]);
822 $this->assertEquals(false, $assign->can_grade());
823 $this->setUser($this->editingteachers[0]);
824 $this->assertEquals(true, $assign->can_grade());
825 $this->setUser($this->teachers[0]);
826 $this->assertEquals(true, $assign->can_grade());
827
828 // Test the viewgrades capability - without mod/assign:grade.
829 $this->setUser($this->students[0]);
830 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
831 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
832 $this->assertEquals(false, $assign->can_grade());
833 }
834
47f48152 835 public function test_can_view_submission() {
4a47008c
DW
836 global $DB;
837
e6cc5347 838 $this->create_extra_users();
47f48152
DW
839 $this->setUser($this->editingteachers[0]);
840 $assign = $this->create_instance();
841
842 $this->setUser($this->students[0]);
843 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
844 $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
845 $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
846 $this->setUser($this->teachers[0]);
847 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
848 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
849 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 850 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
851 $this->setUser($this->editingteachers[0]);
852 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
853 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
854 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 855 $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
4a47008c
DW
856
857 // Test the viewgrades capability - without mod/assign:grade.
858 $this->setUser($this->students[0]);
859 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
860 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
861 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
862 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
863 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
864 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
865 }
866
867
868 public function test_update_submission() {
df211804 869 $this->create_extra_users();
47f48152
DW
870 $this->setUser($this->editingteachers[0]);
871 $assign = $this->create_instance();
872
a5c793c3 873 $this->setUser($this->extrastudents[0]);
47f48152 874 $now = time();
a5c793c3
DW
875 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
876 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
877
878 $this->setUser($this->teachers[0]);
879 // Verify the gradebook update.
880 $gradinginfo = grade_get_grades($this->course->id,
881 'mod',
882 'assign',
883 $assign->get_instance()->id,
a5c793c3 884 $this->extrastudents[0]->id);
47f48152 885
a5c793c3
DW
886 $this->assertEquals($this->extrastudents[0]->id,
887 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
888
889 // Now verify group assignments.
890 $this->setUser($this->editingteachers[0]);
891 $assign = $this->create_instance(array('teamsubmission'=>1));
892
a5c793c3 893 $this->setUser($this->extrastudents[0]);
47f48152 894 $now = time();
a5c793c3
DW
895 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
896 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
47f48152 897
e6cc5347 898 // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
47f48152
DW
899
900 $this->setUser($this->editingteachers[0]);
901 $gradinginfo = grade_get_grades($this->course->id,
902 'mod',
903 'assign',
904 $assign->get_instance()->id,
a5c793c3 905 $this->extrastudents[0]->id);
47f48152 906
a5c793c3
DW
907 $this->assertEquals($this->extrastudents[0]->id,
908 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
909
910 $gradinginfo = grade_get_grades($this->course->id,
911 'mod',
912 'assign',
913 $assign->get_instance()->id,
a5c793c3 914 $this->extrastudents[self::GROUP_COUNT]->id);
47f48152 915
a5c793c3
DW
916 $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
917 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
47f48152 918
e6cc5347
RT
919 $gradinginfo = grade_get_grades($this->course->id,
920 'mod',
921 'assign',
922 $assign->get_instance()->id,
923 $this->extrasuspendedstudents[0]->id);
924 $this->assertEquals($this->extrasuspendedstudents[0]->id,
925 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
926
927 // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
928 $this->setUser($this->editingteachers[0]);
929 $assign = $this->create_instance(array('teamsubmission'=>1));
930
931 $this->setUser($this->extrastudents[1]);
932 $now = time();
933 $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
934 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
935
936 $this->setUser($this->teachers[0]);
937 $gradinginfo = grade_get_grades($this->course->id,
938 'mod',
939 'assign',
940 $assign->get_instance()->id,
941 $this->extrastudents[1]->id);
942
943 $this->assertEquals($this->extrastudents[1]->id,
944 $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
945
946 $gradinginfo = grade_get_grades($this->course->id,
947 'mod',
948 'assign',
949 $assign->get_instance()->id,
950 $this->extrastudents[self::GROUP_COUNT+1]->id);
951
952 $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
953 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
954
955 $gradinginfo = grade_get_grades($this->course->id,
956 'mod',
957 'assign',
958 $assign->get_instance()->id,
959 $this->extrasuspendedstudents[1]->id);
960 $this->assertEquals($this->extrasuspendedstudents[1]->id,
961 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
962
47f48152
DW
963 // Now verify blind marking.
964 $this->setUser($this->editingteachers[0]);
965 $assign = $this->create_instance(array('blindmarking'=>1));
966
a5c793c3 967 $this->setUser($this->extrastudents[0]);
47f48152 968 $now = time();
a5c793c3
DW
969 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
970 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
971
972 $this->setUser($this->editingteachers[0]);
973 $gradinginfo = grade_get_grades($this->course->id,
974 'mod',
975 'assign',
976 $assign->get_instance()->id,
a5c793c3 977 $this->extrastudents[0]->id);
47f48152 978
a5c793c3 979 $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
47f48152
DW
980 }
981
79397b56 982 public function test_group_submissions_submit_for_marking_requireallteammemberssubmit() {
2bd27878
DW
983 global $PAGE;
984
985 $this->create_extra_users();
986 // Now verify group assignments.
987 $this->setUser($this->editingteachers[0]);
988 $assign = $this->create_instance(array('teamsubmission'=>1,
989 'assignsubmission_onlinetext_enabled'=>1,
990 'submissiondrafts'=>1,
991 'requireallteammemberssubmit'=>1));
992 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
993
2bd27878 994 // Add a submission.
79397b56 995 $this->setUser($this->extrastudents[0]);
2bd27878
DW
996 $data = new stdClass();
997 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
998 'text'=>'Submission text',
999 'format'=>FORMAT_MOODLE);
1000
1001 $notices = array();
1002 $assign->save_submission($data, $notices);
1003
1004 // Check we can see the submit button.
1005 $output = $assign->view_student_summary($this->extrastudents[0], true);
1006 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1007
1008 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1009 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1010 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1011
1012 // Check that the student does not see "Submit" button.
1013 $output = $assign->view_student_summary($this->extrastudents[0], true);
1014 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1015
1016 // Change to another user in the same group.
1017 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1018 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1019 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1020
1021 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1022 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1023 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1024 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1025 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1026 }
1027
79397b56
DB
1028 public function test_group_submissions_submit_for_marking() {
1029 global $PAGE;
1030
1031 $this->create_extra_users();
1032 // Now verify group assignments.
1033 $this->setUser($this->editingteachers[0]);
a0f8db77 1034 $time = time();
79397b56
DB
1035 $assign = $this->create_instance(array('teamsubmission'=>1,
1036 'assignsubmission_onlinetext_enabled'=>1,
1037 'submissiondrafts'=>1,
1038 'requireallteammemberssubmit'=>0,
a0f8db77 1039 'duedate' => $time - 2*24*60*60));
79397b56
DB
1040 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1041
1042 $this->setUser($this->extrastudents[0]);
1043 // Add a submission.
1044 $data = new stdClass();
1045 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1046 'text'=>'Submission text',
1047 'format'=>FORMAT_MOODLE);
1048
1049 $notices = array();
1050 $assign->save_submission($data, $notices);
1051
1052 // Check we can see the submit button.
1053 $output = $assign->view_student_summary($this->extrastudents[0], true);
1054 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1055 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1056 $difftime = time() - $time;
1057 $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1058
1059 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1060 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1061 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1062
1063 // Check that the student does not see "Submit" button.
1064 $output = $assign->view_student_summary($this->extrastudents[0], true);
1065 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1066
1067 // Change to another user in the same group.
1068 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1069 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1070 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1071
1072 // Check that time remaining is not overdue.
1073 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1074 $difftime = time() - $time;
1075 $this->assertContains(get_string('submittedlate', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1076
1077 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1078 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1079 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1080 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1081 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1082 }
1083
47f48152
DW
1084 public function test_submissions_open() {
1085 $this->setUser($this->editingteachers[0]);
1086
1087 $now = time();
1088 $tomorrow = $now + 24*60*60;
1089 $oneweek = $now + 7*24*60*60;
1090 $yesterday = $now - 24*60*60;
1091
1092 $assign = $this->create_instance();
1093 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1094
1095 $assign = $this->create_instance(array('duedate'=>$tomorrow));
1096 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1097
1098 $assign = $this->create_instance(array('duedate'=>$yesterday));
1099 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1100
1101 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
1102 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1103
1104 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
1105 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1106
1107 $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
1108 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1109
1110 $assign = $this->create_instance(array('submissiondrafts'=>1));
1111 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1112
1113 $this->setUser($this->students[0]);
1114 $now = time();
1115 $submission = $assign->get_user_submission($this->students[0]->id, true);
1116 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1117 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1118 $this->setUser($this->editingteachers[0]);
1119 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1120 }
1121
1122 public function test_get_graders() {
df211804 1123 $this->create_extra_users();
47f48152 1124 $this->setUser($this->editingteachers[0]);
47f48152 1125
f268fb5d
DW
1126 // Create an assignment with no groups.
1127 $assign = $this->create_instance();
a5c793c3
DW
1128 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1129 self::DEFAULT_EDITING_TEACHER_COUNT +
1130 self::EXTRA_TEACHER_COUNT +
1131 self::EXTRA_EDITING_TEACHER_COUNT,
1132 $assign->testable_get_graders($this->students[0]->id));
47f48152 1133
47f48152 1134 // Force create an assignment with SEPARATEGROUPS.
f268fb5d
DW
1135 $data = new stdClass();
1136 $data->courseid = $this->course->id;
1137 $data->name = 'Grouping';
1138 $groupingid = groups_create_grouping($data);
1139 groups_assign_grouping($groupingid, $this->groups[0]->id);
1140 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
47f48152
DW
1141
1142 $this->setUser($this->students[1]);
a5c793c3 1143 $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
f268fb5d
DW
1144 // Note the second student is in a group that is not in the grouping.
1145 // This means that we get all graders that are not in a group in the grouping.
1146 $this->assertCount(10, $assign->testable_get_graders($this->students[1]->id));
47f48152
DW
1147 }
1148
83360c8d
S
1149 public function test_get_notified_users() {
1150 global $CFG, $DB;
1151
1152 $capability = 'mod/assign:receivegradernotifications';
1153 $coursecontext = context_course::instance($this->course->id);
1154 $role = $DB->get_record('role', array('shortname' => 'teacher'));
1155
1156 $this->create_extra_users();
1157 $this->setUser($this->editingteachers[0]);
1158
1159 // Create an assignment with no groups.
1160 $assign = $this->create_instance();
1161
1162 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1163 self::DEFAULT_EDITING_TEACHER_COUNT +
1164 self::EXTRA_TEACHER_COUNT +
1165 self::EXTRA_EDITING_TEACHER_COUNT,
1166 $assign->testable_get_notifiable_users($this->students[0]->id));
1167
1168 // Change nonediting teachers role to not receive grader notifications.
1169 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1170
1171 $this->assertCount(self::DEFAULT_EDITING_TEACHER_COUNT +
1172 self::EXTRA_EDITING_TEACHER_COUNT,
1173 $assign->testable_get_notifiable_users($this->students[0]->id));
1174
1175 // Reset nonediting teachers role to default.
1176 unassign_capability($capability, $role->id, $coursecontext);
1177
1178 // Force create an assignment with SEPARATEGROUPS.
1179 $data = new stdClass();
1180 $data->courseid = $this->course->id;
1181 $data->name = 'Grouping';
1182 $groupingid = groups_create_grouping($data);
1183 groups_assign_grouping($groupingid, $this->groups[0]->id);
1184 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
1185
1186 $this->setUser($this->students[1]);
1187 $this->assertCount(4, $assign->testable_get_notifiable_users($this->students[0]->id));
1188 // Note the second student is in a group that is not in the grouping.
1189 // This means that we get all graders that are not in a group in the grouping.
1190 $this->assertCount(10, $assign->testable_get_notifiable_users($this->students[1]->id));
1191
1192 // Change nonediting teachers role to not receive grader notifications.
1193 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1194
1195 $this->assertCount(2, $assign->testable_get_notifiable_users($this->students[0]->id));
1196 // Note the second student is in a group that is not in the grouping.
1197 // This means that we get all graders that are not in a group in the grouping.
1198 $this->assertCount(5, $assign->testable_get_notifiable_users($this->students[1]->id));
1199 }
1200
20b7dcfc
DW
1201 public function test_group_members_only() {
1202 global $CFG;
1203
1204 $this->setAdminUser();
1205 $this->create_extra_users();
c13ac85d 1206 $CFG->enableavailability = true;
20b7dcfc
DW
1207 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
1208 groups_assign_grouping($grouping->id, $this->groups[0]->id);
1209
1210 // Force create an assignment with SEPARATEGROUPS.
1211 $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
c13ac85d 1212 array('availability' => json_encode(\core_availability\tree::get_root_json(array(
1213 \availability_grouping\condition::get_json()))),
1214 'groupingid' => $grouping->id));
20b7dcfc
DW
1215
1216 $cm = get_coursemodule_from_instance('assign', $instance->id);
1217 $context = context_module::instance($cm->id);
1218 $assign = new testable_assign($context, $cm, $this->course);
1219
1220 $this->setUser($this->teachers[0]);
8270f0d0 1221 get_fast_modinfo($this->course, 0, true);
20b7dcfc
DW
1222 $this->assertCount(5, $assign->list_participants(0, true));
1223
1224 }
1225
47f48152
DW
1226 public function test_get_uniqueid_for_user() {
1227 $this->setUser($this->editingteachers[0]);
1228 $assign = $this->create_instance();
1229
1230 foreach ($this->students as $student) {
1231 $uniqueid = $assign->get_uniqueid_for_user($student->id);
1232 $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
1233 }
1234 }
1235
46692c3a 1236 public function test_show_student_summary() {
c2114099 1237 global $CFG, $PAGE;
46692c3a
DW
1238
1239 $this->setUser($this->editingteachers[0]);
1240 $assign = $this->create_instance();
c2114099 1241 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
46692c3a
DW
1242
1243 // No feedback should be available because this student has not been graded.
1244 $this->setUser($this->students[0]);
1245 $output = $assign->view_student_summary($this->students[0], true);
1246 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
1247 // Simulate adding a grade.
1248 $this->setUser($this->teachers[0]);
1249 $data = new stdClass();
1250 $data->grade = '50.0';
df211804 1251 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
46692c3a 1252
b0da618b 1253 // Now we should see the feedback.
46692c3a
DW
1254 $this->setUser($this->students[0]);
1255 $output = $assign->view_student_summary($this->students[0], true);
1256 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
1257
1258 // Now hide the grade in gradebook.
1259 $this->setUser($this->teachers[0]);
1260 require_once($CFG->libdir.'/gradelib.php');
1261 $gradeitem = new grade_item(array(
1262 'itemtype' => 'mod',
1263 'itemmodule' => 'assign',
1264 'iteminstance' => $assign->get_instance()->id,
1265 'courseid' => $this->course->id));
1266
1267 $gradeitem->set_hidden(1, false);
1268
1269 // No feedback should be available because the grade is hidden.
1270 $this->setUser($this->students[0]);
1271 $output = $assign->view_student_summary($this->students[0], true);
1272 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
1273
b0da618b 1274 // Do the same but add feedback.
46692c3a
DW
1275 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
1276
1277 $this->setUser($this->teachers[0]);
1278 $grade = $assign->get_user_grade($this->students[0]->id, true);
1279 $data = new stdClass();
1280 $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
1281 'format'=>FORMAT_MOODLE);
1282 $plugin = $assign->get_feedback_plugin_by_type('comments');
1283 $plugin->save($grade, $data);
1284
b0da618b 1285 // Should have feedback but no grade.
46692c3a
DW
1286 $this->setUser($this->students[0]);
1287 $output = $assign->view_student_summary($this->students[0], true);
ea698284 1288 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
46692c3a
DW
1289 $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
1290 $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
45aac51a 1291
ea698284
AD
1292 // Now hide the grade in gradebook.
1293 $this->setUser($this->teachers[0]);
1294 $gradeitem = new grade_item(array(
1295 'itemtype' => 'mod',
1296 'itemmodule' => 'assign',
1297 'iteminstance' => $assign->get_instance()->id,
1298 'courseid' => $this->course->id));
1299
1300 $gradeitem->set_hidden(1, false);
1301
1302 // No feedback should be available because the grade is hidden.
1303 $this->setUser($this->students[0]);
1304 $output = $assign->view_student_summary($this->students[0], true);
1305 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
46692c3a
DW
1306 }
1307
df211804
DW
1308 public function test_attempt_reopen_method_manual() {
1309 global $PAGE;
1310
1311 $this->setUser($this->editingteachers[0]);
1312 $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
1313 'maxattempts'=>3,
1314 'submissiondrafts'=>1,
1315 'assignsubmission_onlinetext_enabled'=>1));
1316 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1317
1318 // Student should be able to see an add submission button.
1319 $this->setUser($this->students[0]);
1320 $output = $assign->view_student_summary($this->students[0], true);
1321 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1322
1323 // Add a submission.
1324 $now = time();
1325 $submission = $assign->get_user_submission($this->students[0]->id, true);
1326 $data = new stdClass();
1327 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1328 'text'=>'Submission text',
1329 'format'=>FORMAT_MOODLE);
1330 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1331 $plugin->save($submission, $data);
1332
1333 // And now submit it for marking.
1334 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1335 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1336
1337 // Verify the student cannot make changes to the submission.
1338 $output = $assign->view_student_summary($this->students[0], true);
1339 $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1340
1341 // Mark the submission.
1342 $this->setUser($this->teachers[0]);
1343 $data = new stdClass();
1344 $data->grade = '50.0';
1345 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1346
1347 // Check the student can see the grade.
1348 $this->setUser($this->students[0]);
1349 $output = $assign->view_student_summary($this->students[0], true);
1350 $this->assertNotEquals(false, strpos($output, '50.0'));
1351
1352 // Allow the student another attempt.
1353 $this->teachers[0]->ignoresesskey = true;
1354 $this->setUser($this->teachers[0]);
1355 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1356 $this->assertEquals(true, $result);
1357
1358 // Check that the previous attempt is now in the submission history table.
1359 $this->setUser($this->students[0]);
1360 $output = $assign->view_student_summary($this->students[0], true);
1361 // Need a better check.
1362 $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
1363
1364 // Check that the student now has a button for Add a new attempt".
1365 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1366 // Check that the student now does not have a button for Submit.
1367 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
1368
1369 // Check that the student now has a submission history.
1370 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
1371
1372 $this->setUser($this->teachers[0]);
1373 // Check that the grading table loads correctly and contains this user.
1374 // This is also testing that we do not get duplicate rows in the grading table.
1375 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1376 $output = $assign->get_renderer()->render($gradingtable);
1377 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1378
1379 // Should be 1 not 2.
1380 $this->assertEquals(1, $assign->count_submissions());
1381 $this->assertEquals(1, $assign->count_submissions_with_status('reopened'));
1382 $this->assertEquals(0, $assign->count_submissions_need_grading());
1383 $this->assertEquals(1, $assign->count_grades());
1384
1385 // Change max attempts to unlimited.
1386 $formdata = clone($assign->get_instance());
1387 $formdata->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS;
1388 $formdata->instance = $formdata->id;
1389 $assign->update_instance($formdata);
1390
9e3eee67
DW
1391 // Mark the submission again.
1392 $data = new stdClass();
1393 $data->grade = '60.0';
1394 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1395
1396 // Check the grade exists.
1397 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
1398 $this->assertEquals(60, (int)$grades[$this->students[0]->id]->rawgrade);
1399
1400 // Check we can reopen still.
df211804
DW
1401 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1402 $this->assertEquals(true, $result);
1403
9e3eee67 1404 // Should no longer have a grade because there is no grade for the latest attempt.
df211804 1405 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
9e3eee67 1406 $this->assertEmpty($grades);
df211804 1407
df211804 1408 }
46692c3a 1409
f8d107b3
DM
1410 public function test_markingworkflow() {
1411 global $PAGE;
1412
1413 $this->setUser($this->editingteachers[0]);
1414 $assign = $this->create_instance(array('markingworkflow'=>1));
1415 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1416
13e82f1c 1417 // Mark the submission and set to notmarked.
f8d107b3
DM
1418 $this->setUser($this->teachers[0]);
1419 $data = new stdClass();
1420 $data->grade = '50.0';
1421 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
1422 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1423
1424 // Check the student can't see the grade.
1425 $this->setUser($this->students[0]);
1426 $output = $assign->view_student_summary($this->students[0], true);
1427 $this->assertEquals(false, strpos($output, '50.0'));
1428
13e82f1c 1429 // Mark the submission and set to inmarking.
f8d107b3
DM
1430 $this->setUser($this->teachers[0]);
1431 $data = new stdClass();
1432 $data->grade = '50.0';
1433 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
1434 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1435
1436 // Check the student can't see the grade.
1437 $this->setUser($this->students[0]);
1438 $output = $assign->view_student_summary($this->students[0], true);
1439 $this->assertEquals(false, strpos($output, '50.0'));
1440
13e82f1c 1441 // Mark the submission and set to readyforreview.
f8d107b3
DM
1442 $this->setUser($this->teachers[0]);
1443 $data = new stdClass();
1444 $data->grade = '50.0';
1445 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
1446 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1447
1448 // Check the student can't see the grade.
1449 $this->setUser($this->students[0]);
1450 $output = $assign->view_student_summary($this->students[0], true);
1451 $this->assertEquals(false, strpos($output, '50.0'));
1452
13e82f1c 1453 // Mark the submission and set to inreview.
f8d107b3
DM
1454 $this->setUser($this->teachers[0]);
1455 $data = new stdClass();
1456 $data->grade = '50.0';
1457 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
1458 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1459
1460 // Check the student can't see the grade.
1461 $this->setUser($this->students[0]);
1462 $output = $assign->view_student_summary($this->students[0], true);
1463 $this->assertEquals(false, strpos($output, '50.0'));
1464
13e82f1c 1465 // Mark the submission and set to readyforrelease.
f8d107b3
DM
1466 $this->setUser($this->teachers[0]);
1467 $data = new stdClass();
1468 $data->grade = '50.0';
1469 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
1470 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1471
1472 // Check the student can't see the grade.
1473 $this->setUser($this->students[0]);
1474 $output = $assign->view_student_summary($this->students[0], true);
1475 $this->assertEquals(false, strpos($output, '50.0'));
1476
13e82f1c 1477 // Mark the submission and set to released.
f8d107b3
DM
1478 $this->setUser($this->teachers[0]);
1479 $data = new stdClass();
1480 $data->grade = '50.0';
1481 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
1482 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1483
1484 // Check the student can see the grade.
1485 $this->setUser($this->students[0]);
1486 $output = $assign->view_student_summary($this->students[0], true);
1487 $this->assertNotEquals(false, strpos($output, '50.0'));
1488 }
1489
1490 public function test_markerallocation() {
1491 global $PAGE;
1492
1493 $this->setUser($this->editingteachers[0]);
13e82f1c 1494 $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
f8d107b3
DM
1495 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1496
13e82f1c 1497 // Allocate marker to submission.
f8d107b3
DM
1498 $data = new stdClass();
1499 $data->allocatedmarker = $this->teachers[0]->id;
1500 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1501
13e82f1c 1502 // Check the allocated marker can view the submission.
f8d107b3
DM
1503 $this->setUser($this->teachers[0]);
1504 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1505 $output = $assign->get_renderer()->render($gradingtable);
1506 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1507
13e82f1c 1508 // Check that other teachers can't view this submission.
f8d107b3
DM
1509 $this->setUser($this->teachers[1]);
1510 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1511 $output = $assign->get_renderer()->render($gradingtable);
1512 $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
1513 }
76e77b05 1514
3d1331be 1515
159b7f40 1516
57fbd5f9
DW
1517 public function test_teacher_submit_for_student() {
1518 global $PAGE;
1519
1520 $this->preventResetByRollback();
1521 $sink = $this->redirectMessages();
1522
1523 $this->setUser($this->editingteachers[0]);
1524
1525 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
1526 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1527
1528 $this->setUser($this->students[0]);
1529 // Simulate a submission.
1530 $data = new stdClass();
1531 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1532 'text'=>'Student submission text',
1533 'format'=>FORMAT_MOODLE);
1534
1535 $notices = array();
1536 $assign->save_submission($data, $notices);
1537
1538 // Check that the submission text was saved.
1539 $output = $assign->view_student_summary($this->students[0], true);
1540 $this->assertContains('Student submission text', $output, 'Contains student submission text');
1541
1542 // Check that a teacher teacher with the extra capability can edit a students submission.
1543 $this->setUser($this->teachers[0]);
1544 $data = new stdClass();
1545 $data->userid = $this->students[0]->id;
1546 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1547 'text'=>'Teacher edited submission text',
1548 'format'=>FORMAT_MOODLE);
1549
1550 // Add the required capability.
1551 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
1552 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
1553 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
1554 accesslib_clear_all_caches_for_unit_testing();
1555
1556 // Try to save the submission.
1557 $notices = array();
1558 $assign->save_submission($data, $notices);
1559
1560 // Check that the teacher can submit the students work.
1561 $data = new stdClass();
1562 $data->userid = $this->students[0]->id;
1563 $notices = array();
1564 $assign->submit_for_grading($data, $notices);
1565
1566 // Revert to draft so the student can edit it.
1567 $assign->revert_to_draft($this->students[0]->id);
1568
1569 $this->setUser($this->students[0]);
1570
1571 // Check that the submission text was saved.
1572 $output = $assign->view_student_summary($this->students[0], true);
1573 $this->assertContains('Teacher edited submission text', $output, 'Contains student submission text');
1574
1575 // Check that the student can submit their work.
1576 $data = new stdClass();
1577 $assign->submit_for_grading($data, $notices);
1578
1579 $output = $assign->view_student_summary($this->students[0], true);
1580 $this->assertNotContains(get_string('addsubmission', 'assign'), $output);
1581
1582 // Set to a default editing teacher who should not be able to edit this submission.
1583 $this->setUser($this->editingteachers[1]);
1584
1585 // Revert to draft so the submission is editable.
1586 $assign->revert_to_draft($this->students[0]->id);
1587
1588 $data = new stdClass();
1589 $data->userid = $this->students[0]->id;
1590 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1591 'text'=>'Teacher 2 edited submission text',
1592 'format'=>FORMAT_MOODLE);
1593
1594 $notices = array();
1595 $this->setExpectedException('moodle_exception');
1596 $assign->save_submission($data, $notices);
1597
1598 $sink->close();
1599 }
1600
9054c04d 1601 public function test_disable_submit_after_cutoff_date() {
1602 global $PAGE;
1603
1604 $this->setUser($this->editingteachers[0]);
1605 $now = time();
1606 $tomorrow = $now + 24*60*60;
1607 $lastweek = $now - 7*24*60*60;
1608 $yesterday = $now - 24*60*60;
1609
1610 $assign = $this->create_instance(array('duedate'=>$yesterday,
1611 'cutoffdate'=>$tomorrow,
1612 'assignsubmission_onlinetext_enabled'=>1));
1613 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1614
1615 // Student should be able to see an add submission button.
1616 $this->setUser($this->students[0]);
1617 $output = $assign->view_student_summary($this->students[0], true);
1618 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1619
1620 // Add a submission but don't submit now.
1621 $submission = $assign->get_user_submission($this->students[0]->id, true);
1622 $data = new stdClass();
1623 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1624 'text'=>'Submission text',
1625 'format'=>FORMAT_MOODLE);
1626 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1627 $plugin->save($submission, $data);
1628
1629 // Create another instance with cut-off and due-date already passed.
1630 $this->setUser($this->editingteachers[0]);
1631 $now = time();
1632 $assign = $this->create_instance(array('duedate'=>$lastweek,
1633 'cutoffdate'=>$yesterday,
1634 'assignsubmission_onlinetext_enabled'=>1));
1635
1636 $this->setUser($this->students[0]);
1637 $output = $assign->view_student_summary($this->students[0], true);
1638 $this->assertNotContains($output, get_string('editsubmission', 'assign'),
1639 'Should not be able to edit after cutoff date.');
1640 $this->assertNotContains($output, get_string('submitassignment', 'assign'),
1641 'Should not be able to submit after cutoff date.');
1642 }
f159ad73 1643 /**
1644 * Testing for submission comment plugin settings
1645 */
1646 public function test_submission_comment_plugin_settings() {
1647 global $CFG;
1648
1649 $commentconfig = false;
1650 if (!empty($CFG->usecomments)) {
1651 $commentconfig = $CFG->usecomments;
1652 }
1653
1654 $CFG->usecomments = true;
1655 $assign = $this->create_instance();
1656 $plugin = $assign->get_submission_plugin_by_type('comments');
1657 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1658
1659 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
1660 $plugin = $assign->get_submission_plugin_by_type('comments');
1661 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1662
1663 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
1664 $plugin = $assign->get_submission_plugin_by_type('comments');
1665 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1666
1667 $CFG->usecomments = false;
1668 $assign = $this->create_instance();
1669 $plugin = $assign->get_submission_plugin_by_type('comments');
1670 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1671
1672 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
1673 $plugin = $assign->get_submission_plugin_by_type('comments');
1674 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1675
1676 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
1677 $plugin = $assign->get_submission_plugin_by_type('comments');
1678 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1679
1680 $CFG->usecomments = $commentconfig;
1681 }
1682
c7a73689
DW
1683 /**
1684 * Testing for comment inline settings
1685 */
1686 public function test_feedback_comment_commentinline() {
1687 global $CFG;
1688
1689 $sourcetext = "Hello!
1690
1691I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
1692
1693URL outside a tag: https://moodle.org/logo/logo-240x60.gif
1694Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
1695
1696External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/>
1697External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\"/>
1698Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/>
1699Internal link 2:<img alt=\"Moodle\" src=\"@@PLUGINFILE@@logo-240x60.gif\"/>
1700Anchor link 1:<a href=\"@@PLUGINFILE@@logo-240x60.gif\" alt=\"bananas\">Link text</a>
1701Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
1702";
1703
1704 // Note the internal images have been stripped and the html is purified (quotes fixed in this case).
1705 $filteredtext = "Hello!
1706
1707I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
1708
1709URL outside a tag: https://moodle.org/logo/logo-240x60.gif
1710Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
1711
1712External link 1:<img src=\"https://moodle.org/logo/logo-240x60.gif\" alt=\"Moodle\" />
1713External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\" />
1714Internal link 1:
1715Internal link 2:
1716Anchor link 1:Link text
1717Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
1718";
1719
1720 $this->setUser($this->editingteachers[0]);
1721 $params = array('assignsubmission_onlinetext_enabled' => 1,
1722 'assignfeedback_comments_enabled' => 1,
1723 'assignfeedback_comments_commentinline' => 1);
1724 $assign = $this->create_instance($params);
1725
1726 $this->setUser($this->students[0]);
1727 // Add a submission but don't submit now.
1728 $submission = $assign->get_user_submission($this->students[0]->id, true);
1729 $data = new stdClass();
1730
1731 // Test the internal link is stripped, but the external one is not.
1732 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1733 'text'=>$sourcetext,
1734 'format'=>FORMAT_MOODLE);
1735
1736 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1737 $plugin->save($submission, $data);
1738
1739 $this->setUser($this->editingteachers[0]);
1740
1741 $data = new stdClass();
1742 require_once($CFG->dirroot . '/mod/assign/gradeform.php');
1743 $pagination = array('userid'=>$this->students[0]->id,
1744 'rownum'=>0,
1745 'last'=>true,
1746 'useridlistid'=>time(),
1747 'attemptnumber'=>0);
1748 $formparams = array($assign, $data, $pagination);
1749 $mform = new mod_assign_grade_form(null, $formparams);
1750
1751 $this->assertEquals($filteredtext, $data->assignfeedbackcomments_editor['text']);
1752 }
1753
f159ad73 1754 /**
1755 * Testing for feedback comment plugin settings
1756 */
1757 public function test_feedback_plugin_settings() {
1758
1759 $assign = $this->create_instance();
1760 $plugin = $assign->get_feedback_plugin_by_type('comments');
1761 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1762
1763 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 0));
1764 $plugin = $assign->get_feedback_plugin_by_type('comments');
1765 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1766
1767 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
1768 $plugin = $assign->get_feedback_plugin_by_type('comments');
1769 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1770 }
456d7bc7
RT
1771
1772 /**
1773 * Testing if gradebook feedback plugin is enabled.
1774 */
1775 public function test_is_gradebook_feedback_enabled() {
1776 $adminconfig = get_config('assign');
1777 $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
1778
1779 // Create assignment with gradebook feedback enabled and grade = 0.
1780 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 1, 'grades' => 0));
1781
1782 // Get gradebook feedback plugin.
1783 $gradebookplugintype = str_replace('assignfeedback_', '', $gradebookplugin);
1784 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
1785 $this->assertEquals(1, $plugin->is_enabled('enabled'));
1786 $this->assertEquals(1, $assign->is_gradebook_feedback_enabled());
1787
1788 // Create assignment with gradebook feedback disabled and grade = 0.
1789 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 0, 'grades' => 0));
1790 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
1791 $this->assertEquals(0, $plugin->is_enabled('enabled'));
1792 }
57fbd5f9
DW
1793
1794 /**
1795 * Testing can_edit_submission
1796 */
1797 public function test_can_edit_submission() {
1798 global $PAGE, $DB;
1799 $this->create_extra_users();
1800
1801 $this->setAdminUser();
1802 // Create assignment (onlinetext).
1803 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
1804 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1805
1806 // Check student can edit their own submission.
1807 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->students[0]->id));
1808 // Check student cannot edit others submission.
1809 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->students[1]->id));
1810
1811 // Check teacher cannot (by default) edit a students submission.
1812 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
1813
1814 // Add the required capability to edit a student submission.
1815 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
1816 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
1817 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
1818 accesslib_clear_all_caches_for_unit_testing();
1819 // Retest - should now have access.
1820 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
1821
1822 // Force create an assignment with SEPARATEGROUPS.
1823 $data = new stdClass();
1824 $data->courseid = $this->course->id;
1825 $data->name = 'Grouping';
1826 $groupingid = groups_create_grouping($data);
1827 groups_assign_grouping($groupingid, $this->groups[0]->id);
1828 groups_assign_grouping($groupingid, $this->groups[1]->id);
1829 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
1830
1831 // Add the capability to the new assignment for extra students 0 and 1.
1832 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
1833 role_assign($roleid, $this->extrastudents[0]->id, $assign->get_context()->id);
1834 role_assign($roleid, $this->extrastudents[1]->id, $assign->get_context()->id);
1835 accesslib_clear_all_caches_for_unit_testing();
1836
1837 // Verify the extra student does not have the capability to edit a submission not in their group.
1838 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[1]->id));
1839 // Verify the extra student does have the capability to edit a submission in their group.
1840 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[0]->id));
1841
1842 }
323f221b
MH
1843
1844 /**
1845 * Test if the view blind details capability works
1846 */
1847 public function test_can_view_blind_details() {
1848 global $PAGE, $DB;
1849 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
1850 $managerrole = $DB->get_record('role', array('shortname' => 'manager'));
1851
1852 $student = $this->students[0];// Get a student user.
1853 // Create a teacher. Shouldn't be able to view blind marking ID.
1854 $teacher = $this->getDataGenerator()->create_user();
1855
1856 $this->getDataGenerator()->enrol_user($teacher->id,
1857 $this->course->id,
1858 $teacherrole->id);
1859
1860 // Create a manager.. Should be able to view blind marking ID.
1861 $manager = $this->getDataGenerator()->create_user();
e28d6b29
MG
1862 $this->getDataGenerator()->enrol_user($manager->id,
1863 $this->course->id,
323f221b
MH
1864 $managerrole->id);
1865
1866 // Generate blind marking assignment.
e28d6b29 1867 $assign = $this->create_instance(array('blindmarking' => 1));
323f221b
MH
1868 $this->assertEquals(true, $assign->is_blind_marking());
1869
1870 // Test student names are hidden to teacher.
e28d6b29
MG
1871 $this->setUser($teacher);
1872 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
1873 $output = $assign->get_renderer()->render($gradingtable);
323f221b
MH
1874 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign'))); // "Participant" is somewhere on the page.
1875 $this->assertEquals(false, strpos($output, fullname($student))); // Students full name doesn't appear.
1876
1877 // Test student names are visible to manager.
e28d6b29
MG
1878 $this->setUser($manager);
1879 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
1880 $output = $assign->get_renderer()->render($gradingtable);
8c674e80 1881 $this->assertEquals(false, strpos($output, get_string('hiddenuser', 'assign')));
323f221b
MH
1882 $this->assertEquals(true, strpos($output, fullname($student))); //students full name doesn't appear.
1883 }
47f48152
DW
1884}
1885