weekly release 3.2dev
[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 87 $this->setUser($this->students[0]);
52f3e060 88 $this->expectException('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 95 $this->setUser($this->teachers[0]);
52f3e060 96 $this->expectException('required_capability_exception');
05a6445a
DW
97 $assign->reveal_identities();
98 $this->teachers[0]->ignoresesskey = false;
47f48152
DW
99
100 // Test sesskey is required.
47f48152 101 $this->setUser($this->editingteachers[0]);
52f3e060 102 $this->expectException('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
80989850
BH
121 /**
122 * Data provider for test_get_assign_perpage
123 *
124 * @return array Provider data
125 */
126 public function get_assign_perpage_provider() {
127 return array(
128 array(
129 'maxperpage' => -1,
130 'userprefs' => array(
131 -1 => -1,
132 10 => 10,
133 20 => 20,
134 50 => 50,
135 ),
136 ),
137 array(
138 'maxperpage' => 15,
139 'userprefs' => array(
140 -1 => 15,
141 10 => 10,
142 20 => 15,
143 50 => 15,
144 ),
145 ),
146 );
147 }
148
149 /**
150 * Test maxperpage
151 *
152 * @dataProvider get_assign_perpage_provider
153 * @param integer $maxperpage site config value
154 * @param array $userprefs Array of user preferences and expected page sizes
155 */
156 public function test_get_assign_perpage($maxperpage, $userprefs) {
157
158 $this->setUser($this->editingteachers[0]);
159 $assign = $this->create_instance();
160 set_config('maxperpage', $maxperpage, 'assign');
161 set_user_preference('assign_perpage', null);
162 $this->assertEquals(10, $assign->get_assign_perpage());
163 foreach ($userprefs as $pref => $perpage) {
164 set_user_preference('assign_perpage', $pref);
165 $this->assertEquals($perpage, $assign->get_assign_perpage());
166 }
167 }
168
79397b56
DB
169 /**
170 * Test submissions with extension date.
171 */
172 public function test_gradingtable_extension_due_date() {
173 global $PAGE;
174
175 // Setup the assignment.
176 $this->create_extra_users();
177 $this->setUser($this->editingteachers[0]);
178 $assign = $this->create_instance(array(
179 'assignsubmission_onlinetext_enabled'=>1,
180 'duedate' => time() - 4 * 24 * 60 * 60,
181 ));
182 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
183 'id' => $assign->get_course_module()->id,
184 'action' => 'grading',
185 )));
186
187 // Check that the assignment is late.
188 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
189 $output = $assign->get_renderer()->render($gradingtable);
190 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
191 $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60)), $output);
192
193 // Grant an extension.
5b460d65
MG
194 $extendedtime = time() + 2 * 24 * 60 * 60;
195 $assign->testable_save_user_extension($this->students[0]->id, $extendedtime);
79397b56
DB
196 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
197 $output = $assign->get_renderer()->render($gradingtable);
198 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
5b460d65 199 $this->assertContains(get_string('userextensiondate', 'assign', userdate($extendedtime)), $output);
79397b56
DB
200
201 // Simulate a submission.
202 $this->setUser($this->students[0]);
203 $submission = $assign->get_user_submission($this->students[0]->id, true);
204 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
205 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
206 $data = new stdClass();
207 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
208 'text'=>'Submission text',
209 'format'=>FORMAT_MOODLE);
210 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
211 $plugin->save($submission, $data);
212
213 // Verify output.
214 $this->setUser($this->editingteachers[0]);
215 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
216 $output = $assign->get_renderer()->render($gradingtable);
217 $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
5b460d65 218 $this->assertContains(get_string('userextensiondate', 'assign', userdate($extendedtime)), $output);
79397b56
DB
219 }
220
221 /**
222 * Test that late submissions with extension date calculate correctly.
223 */
224 public function test_gradingtable_extension_date_calculation_for_lateness() {
225 global $PAGE;
226
227 // Setup the assignment.
228 $this->create_extra_users();
229 $this->setUser($this->editingteachers[0]);
a0f8db77 230 $time = time();
79397b56
DB
231 $assign = $this->create_instance(array(
232 'assignsubmission_onlinetext_enabled'=>1,
a0f8db77 233 'duedate' => $time - 4 * 24 * 60 * 60,
79397b56
DB
234 ));
235 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
236 'id' => $assign->get_course_module()->id,
237 'action' => 'grading',
238 )));
239
240 // Check that the assignment is late.
241 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
242 $output = $assign->get_renderer()->render($gradingtable);
243 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
a0f8db77
DW
244 $difftime = time() - $time;
245 $this->assertContains(get_string('overdue', 'assign', format_time(4*24*60*60 + $difftime)), $output);
79397b56
DB
246
247 // Grant an extension that is in the past.
a0f8db77 248 $assign->testable_save_user_extension($this->students[0]->id, $time - 2 * 24 * 60 * 60);
79397b56
DB
249 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
250 $output = $assign->get_renderer()->render($gradingtable);
251 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
a0f8db77
DW
252 $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
253 $difftime = time() - $time;
254 $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
255
256 // Simulate a submission.
257 $this->setUser($this->students[0]);
258 $submission = $assign->get_user_submission($this->students[0]->id, true);
259 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
260 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
261 $data = new stdClass();
262 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
263 'text'=>'Submission text',
264 'format'=>FORMAT_MOODLE);
265 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
266 $plugin->save($submission, $data);
a0f8db77 267 $submittedtime = time();
79397b56
DB
268
269 // Verify output.
270 $this->setUser($this->editingteachers[0]);
271 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
272 $output = $assign->get_renderer()->render($gradingtable);
273 $this->assertContains(get_string('submissionstatus_submitted', 'assign'), $output);
a0f8db77
DW
274 $this->assertContains(get_string('userextensiondate', 'assign', userdate($time - 2*24*60*60)), $output);
275
276 $difftime = $submittedtime - $time;
277 $this->assertContains(get_string('submittedlateshort', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
278 }
279
232b26f0
CS
280 public function test_gradingtable_status_rendering() {
281 global $PAGE;
282
283 // Setup the assignment.
284 $this->create_extra_users();
285 $this->setUser($this->editingteachers[0]);
286 $time = time();
287 $assign = $this->create_instance(array(
288 'assignsubmission_onlinetext_enabled' => 1,
289 'duedate' => $time - 4 * 24 * 60 * 60,
290 ));
291 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
292 'id' => $assign->get_course_module()->id,
293 'action' => 'grading',
294 )));
295
296 // Check that the assignment is late.
297 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
298 $output = $assign->get_renderer()->render($gradingtable);
299 $this->assertContains(get_string('submissionstatus_', 'assign'), $output);
300 $difftime = time() - $time;
301 $this->assertContains(get_string('overdue', 'assign', format_time(4 * 24 * 60 * 60 + $difftime)), $output);
302
303 // Simulate a student viewing the assignment without submitting.
304 $this->setUser($this->students[0]);
305 $submission = $assign->get_user_submission($this->students[0]->id, true);
306 $submission->status = ASSIGN_SUBMISSION_STATUS_NEW;
307 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
308 $submittedtime = time();
309
310 // Verify output.
311 $this->setUser($this->editingteachers[0]);
312 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
313 $output = $assign->get_renderer()->render($gradingtable);
314 $difftime = $submittedtime - $time;
315 $this->assertContains(get_string('overdue', 'assign', format_time(4 * 24 * 60 * 60 + $difftime)), $output);
316
317 $document = new DOMDocument();
890c2603 318 @$document->loadHTML($output);
232b26f0
CS
319 $xpath = new DOMXPath($document);
320 $this->assertEquals('', $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c8"])'));
321 }
322
79397b56
DB
323 /**
324 * Check that group submission information is rendered correctly in the
325 * grading table.
326 */
327 public function test_gradingtable_group_submissions_rendering() {
328 global $PAGE;
329
330 $this->create_extra_users();
331 // Now verify group assignments.
332 $this->setUser($this->teachers[0]);
333 $assign = $this->create_instance(array(
334 'teamsubmission' => 1,
335 'assignsubmission_onlinetext_enabled' => 1,
336 'submissiondrafts' => 1,
337 'requireallteammemberssubmit' => 0,
338 ));
339 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array(
340 'id' => $assign->get_course_module()->id,
341 'action' => 'grading',
342 )));
343
344 // Add a submission.
345 $this->setUser($this->extrastudents[0]);
346 $data = new stdClass();
347 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
348 'text'=>'Submission text',
349 'format'=>FORMAT_MOODLE);
350 $notices = array();
351 $assign->save_submission($data, $notices);
352
353 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
354 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
355 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
356
357 // Check output.
358 $this->setUser($this->teachers[0]);
359 $gradingtable = new assign_grading_table($assign, 4, '', 0, true);
360 $output = $assign->get_renderer()->render($gradingtable);
361 $document = new DOMDocument();
890c2603 362 @$document->loadHTML($output);
79397b56
DB
363 $xpath = new DOMXPath($document);
364
365 // Check status.
366 $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c4"]/div[@class="submissionstatussubmitted"])'));
367 $this->assertSame(get_string('submissionstatus_submitted', 'assign'), $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c4"]/div[@class="submissionstatussubmitted"])'));
368
369 // Check submission last modified date
370 $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c8"])')));
371 $this->assertGreaterThan(0, strtotime($xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c8"])')));
372
373 // Check group.
374 $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c5"])'));
375 $this->assertSame($this->groups[0]->name, $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c5"])'));
376
377 // Check submission text.
378 $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r0_c9"]/div/div)'));
379 $this->assertSame('Submission text', $xpath->evaluate('string(//td[@id="mod_assign_grading_r3_c9"]/div/div)'));
380
381 // Check comments can be made.
382 $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r0_c10"]//textarea)'));
383 $this->assertSame(1, (int)$xpath->evaluate('count(//td[@id="mod_assign_grading_r3_c10"]//textarea)'));
384 }
385
47f48152
DW
386 public function test_show_intro() {
387 // Test whether we are showing the intro at the correct times.
388 $this->setUser($this->editingteachers[0]);
389 $assign = $this->create_instance(array('alwaysshowdescription'=>1));
390
391 $this->assertEquals(true, $assign->testable_show_intro());
392
393 $tomorrow = time() + (24*60*60);
394
395 $assign = $this->create_instance(array('alwaysshowdescription'=>0,
396 'allowsubmissionsfromdate'=>$tomorrow));
397 $this->assertEquals(false, $assign->testable_show_intro());
398 $yesterday = time() - (24*60*60);
399 $assign = $this->create_instance(array('alwaysshowdescription'=>0,
400 'allowsubmissionsfromdate'=>$yesterday));
401 $this->assertEquals(true, $assign->testable_show_intro());
402 }
403
404 public function test_has_submissions_or_grades() {
405 $this->setUser($this->editingteachers[0]);
406 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
407
408 $instance = $assign->get_instance();
409
410 // Should start empty.
411 $this->assertEquals(false, $assign->has_submissions_or_grades());
412
413 // Simulate a submission.
414 $this->setUser($this->students[0]);
415 $submission = $assign->get_user_submission($this->students[0]->id, true);
ab14ab74
FM
416
417 // The submission is still new.
418 $this->assertEquals(false, $assign->has_submissions_or_grades());
419
420 // Submit the submission.
421 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
422 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
47f48152
DW
423 $data = new stdClass();
424 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
425 'text'=>'Submission text',
426 'format'=>FORMAT_MOODLE);
427 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
428 $plugin->save($submission, $data);
429
430 // Now test again.
431 $this->assertEquals(true, $assign->has_submissions_or_grades());
432 // Set this back to default.
433 $this->students[0]->ignoresesskey = false;
434 }
435
436 public function test_delete_grades() {
437 $this->setUser($this->editingteachers[0]);
438 $assign = $this->create_instance();
439
440 // Simulate adding a grade.
441 $this->setUser($this->teachers[0]);
442 $data = new stdClass();
443 $data->grade = '50.0';
df211804 444 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
445
446 // Now see if the data is in the gradebook.
447 $gradinginfo = grade_get_grades($this->course->id,
448 'mod',
449 'assign',
450 $assign->get_instance()->id);
451
452 $this->assertNotEquals(0, count($gradinginfo->items));
453
454 $assign->testable_delete_grades();
455 $gradinginfo = grade_get_grades($this->course->id,
456 'mod',
457 'assign',
458 $assign->get_instance()->id);
459
460 $this->assertEquals(0, count($gradinginfo->items));
461 }
462
463 public function test_delete_instance() {
464 $this->setUser($this->editingteachers[0]);
465 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
466
467 // Simulate adding a grade.
468 $this->setUser($this->teachers[0]);
469 $data = new stdClass();
470 $data->grade = '50.0';
df211804 471 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
472
473 // Simulate a submission.
474 $this->setUser($this->students[0]);
475 $submission = $assign->get_user_submission($this->students[0]->id, true);
476 $data = new stdClass();
477 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
478 'text'=>'Submission text',
479 'format'=>FORMAT_MOODLE);
480 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
481 $plugin->save($submission, $data);
482
483 // Now try and delete.
484 $this->assertEquals(true, $assign->delete_instance());
485 }
486
487 public function test_reset_userdata() {
488 global $DB;
489
490 $now = time();
491 $this->setUser($this->editingteachers[0]);
492 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1,
493 'duedate'=>$now));
494
495 // Simulate adding a grade.
496 $this->setUser($this->teachers[0]);
497 $data = new stdClass();
498 $data->grade = '50.0';
df211804 499 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
500
501 // Simulate a submission.
502 $this->setUser($this->students[0]);
503 $submission = $assign->get_user_submission($this->students[0]->id, true);
504 $data = new stdClass();
505 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
506 'text'=>'Submission text',
507 'format'=>FORMAT_MOODLE);
508 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
509 $plugin->save($submission, $data);
510
511 $this->assertEquals(true, $assign->has_submissions_or_grades());
512 // Now try and reset.
513 $data = new stdClass();
514 $data->reset_assign_submissions = 1;
515 $data->reset_gradebook_grades = 1;
516 $data->courseid = $this->course->id;
517 $data->timeshift = 24*60*60;
518 $this->setUser($this->editingteachers[0]);
519 $assign->reset_userdata($data);
520 $this->assertEquals(false, $assign->has_submissions_or_grades());
521
522 // Reload the instance data.
523 $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
524 $this->assertEquals($now + 24*60*60, $instance->duedate);
e63515ba
RT
525
526 // Test reset using assign_reset_userdata().
527 $assignduedate = $instance->duedate; // Keep old updated value for comparison.
528 $data->timeshift = 2*24*60*60;
529 assign_reset_userdata($data);
530 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
531 $this->assertEquals($assignduedate + 2*24*60*60, $instance->duedate);
532
533 // Create one more assignment and reset, make sure time shifted for previous assignment is not changed.
534 $assign2 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1,
535 'duedate' => $now));
536 $assignduedate = $instance->duedate;
537 $data->timeshift = 3*24*60*60;
538 $assign2->reset_userdata($data);
539 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
540 $this->assertEquals($assignduedate, $instance->duedate);
541 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
542 $this->assertEquals($now + 3*24*60*60, $instance2->duedate);
543
544 // Reset both assignments using assign_reset_userdata() and make sure both assignments have same date.
545 $assignduedate = $instance->duedate;
546 $assign2duedate = $instance2->duedate;
547 $data->timeshift = 4*24*60*60;
548 assign_reset_userdata($data);
549 $instance = $DB->get_record('assign', array('id' => $assign->get_instance()->id));
550 $this->assertEquals($assignduedate + 4*24*60*60, $instance->duedate);
551 $instance2 = $DB->get_record('assign', array('id' => $assign2->get_instance()->id));
552 $this->assertEquals($assign2duedate + 4*24*60*60, $instance2->duedate);
47f48152
DW
553 }
554
555 public function test_plugin_settings() {
556 global $DB;
557
558 $now = time();
559 $this->setUser($this->editingteachers[0]);
560 $assign = $this->create_instance(array('assignsubmission_file_enabled'=>1,
561 'assignsubmission_file_maxfiles'=>12,
562 'assignsubmission_file_maxsizebytes'=>10));
563
564 $plugin = $assign->get_submission_plugin_by_type('file');
565 $this->assertEquals('12', $plugin->get_config('maxfilesubmissions'));
566 }
567
568 public function test_update_calendar() {
569 global $DB;
570
47f48152 571 $this->setUser($this->editingteachers[0]);
f588ea50
FM
572 $userctx = context_user::instance($this->editingteachers[0]->id)->id;
573
574 // Hack to pretend that there was an editor involved. We need both $_POST and $_REQUEST, and a sesskey.
575 $draftid = file_get_unused_draft_itemid();
576 $_REQUEST['introeditor'] = $draftid;
577 $_POST['introeditor'] = $draftid;
578 $_POST['sesskey'] = sesskey();
579
580 // Write links to a draft area.
581 $fakearealink1 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">link</a>', 'draftfile.php', $userctx,
582 'user', 'draft', $draftid);
583 $fakearealink2 = file_rewrite_pluginfile_urls('<a href="@@PLUGINFILE@@/pic.gif">new</a>', 'draftfile.php', $userctx,
584 'user', 'draft', $draftid);
585
586 // Create a new assignment with links to a draft area.
587 $now = time();
588 $assign = $this->create_instance(array(
589 'duedate' => $now,
590 'intro' => $fakearealink1,
591 'introformat' => FORMAT_HTML
592 ));
47f48152
DW
593
594 // See if there is an event in the calendar.
595 $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
f588ea50
FM
596 $event = $DB->get_record('event', $params);
597 $this->assertNotEmpty($event);
598 $this->assertSame('link', $event->description); // The pluginfile links are removed.
47f48152 599
f588ea50
FM
600 // Make sure the same works when updating the assignment.
601 $instance = $assign->get_instance();
602 $instance->instance = $instance->id;
603 $instance->intro = $fakearealink2;
604 $instance->introformat = FORMAT_HTML;
605 $assign->update_instance($instance);
606 $params = array('modulename' => 'assign', 'instance' => $assign->get_instance()->id);
607 $event = $DB->get_record('event', $params);
608 $this->assertNotEmpty($event);
609 $this->assertSame('new', $event->description); // The pluginfile links are removed.
ae7638f7
DW
610
611 // Create an assignment with a description that should be hidden.
612 $assign = $this->create_instance(array('duedate'=>$now + 160,
613 'alwaysshowdescription'=>false,
8112670d 614 'allowsubmissionsfromdate'=>$now + 60,
ae7638f7
DW
615 'intro'=>'Some text'));
616
617 // Get the event from the calendar.
618 $params = array('modulename'=>'assign', 'instance'=>$assign->get_instance()->id);
619 $event = $DB->get_record('event', $params);
620
621 $this->assertEmpty($event->description);
8112670d
DW
622
623 // Change the allowsubmissionfromdate to the past - do this directly in the DB
624 // because if we call the assignment update method - it will update the calendar
625 // and we want to test that this works from cron.
626 $DB->set_field('assign', 'allowsubmissionsfromdate', $now - 60, array('id'=>$assign->get_instance()->id));
ae7638f7
DW
627 // Run cron to update the event in the calendar.
628 assign::cron();
629 $event = $DB->get_record('event', $params);
630
631 $this->assertContains('Some text', $event->description);
632
47f48152
DW
633 }
634
635 public function test_update_instance() {
636 global $DB;
637
638 $this->setUser($this->editingteachers[0]);
639 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1));
640
641 $now = time();
642 $instance = $assign->get_instance();
643 $instance->duedate = $now;
644 $instance->instance = $instance->id;
645 $instance->assignsubmission_onlinetext_enabled = 1;
47f48152
DW
646
647 $assign->update_instance($instance);
648
649 $instance = $DB->get_record('assign', array('id'=>$assign->get_instance()->id));
650 $this->assertEquals($now, $instance->duedate);
651 }
652
8fd00a24
DW
653 public function test_cannot_submit_empty() {
654 global $PAGE;
655
656 $this->setUser($this->editingteachers[0]);
657 $assign = $this->create_instance(array('submissiondrafts'=>1));
658
659 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
660
661 // Test you cannot see the submit button for an offline assignment regardless.
662 $this->setUser($this->students[0]);
663 $output = $assign->view_student_summary($this->students[0], true);
664 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Can submit empty offline assignment');
665
666 // Test you cannot see the submit button for an online text assignment with no submission.
667 $this->setUser($this->editingteachers[0]);
668 $instance = $assign->get_instance();
669 $instance->instance = $instance->id;
670 $instance->assignsubmission_onlinetext_enabled = 1;
671
672 $assign->update_instance($instance);
673 $this->setUser($this->students[0]);
674 $output = $assign->view_student_summary($this->students[0], true);
675 $this->assertNotContains(get_string('submitassignment', 'assign'), $output, 'Cannot submit empty onlinetext assignment');
676
677 // Simulate a submission.
678 $submission = $assign->get_user_submission($this->students[0]->id, true);
679 $data = new stdClass();
680 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
681 'text'=>'Submission text',
682 'format'=>FORMAT_MOODLE);
683 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
684 $plugin->save($submission, $data);
685 // Test you can see the submit button for an online text assignment with a submission.
686 $output = $assign->view_student_summary($this->students[0], true);
687 $this->assertContains(get_string('submitassignment', 'assign'), $output, 'Can submit non empty onlinetext assignment');
688 }
689
c89d23ee
CB
690 /**
691 * Test new_submission_empty
692 *
693 * We only test combinations of plugins here. Individual plugins are tested
694 * in their respective test files.
695 *
696 * @dataProvider test_new_submission_empty_testcases
697 * @param string $data The file submission data
698 * @param bool $expected The expected return value
699 */
700 public function test_new_submission_empty($data, $expected) {
701 $this->resetAfterTest();
702 $assign = $this->create_instance(['assignsubmission_file_enabled' => 1,
703 'assignsubmission_file_maxfiles' => 12,
704 'assignsubmission_file_maxsizebytes' => 10,
705 'assignsubmission_onlinetext_enabled' => 1]);
706 $this->setUser($this->students[0]);
707 $submission = new stdClass();
708
709 if ($data['file'] && isset($data['file']['filename'])) {
710 $itemid = file_get_unused_draft_itemid();
711 $submission->files_filemanager = $itemid;
712 $data['file'] += ['contextid' => context_user::instance($this->students[0]->id)->id, 'itemid' => $itemid];
713 $fs = get_file_storage();
714 $fs->create_file_from_string((object)$data['file'], 'Content of ' . $data['file']['filename']);
715 }
716
717 if ($data['onlinetext']) {
718 $submission->onlinetext_editor = ['text' => $data['onlinetext']];
719 }
720
721 $result = $assign->new_submission_empty($submission);
722 $this->assertTrue($result === $expected);
723 }
724
725 /**
726 * Dataprovider for the test_new_submission_empty testcase
727 *
728 * @return array of testcases
729 */
730 public function test_new_submission_empty_testcases() {
731 return [
732 'With file and onlinetext' => [
733 [
734 'file' => [
735 'component' => 'user',
736 'filearea' => 'draft',
737 'filepath' => '/',
738 'filename' => 'not_a_virus.exe'
739 ],
740 'onlinetext' => 'Balin Fundinul Uzbadkhazaddumu'
741 ],
742 false
743 ]
744 ];
745 }
746
47f48152 747 public function test_list_participants() {
c13ac85d 748 global $CFG, $DB;
749
df211804 750 $this->create_extra_users();
47f48152
DW
751 $this->setUser($this->editingteachers[0]);
752 $assign = $this->create_instance(array('grade'=>100));
753
a5c793c3 754 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
e6cc5347
RT
755
756 // Teacher with user preference set should see suspended users as well.
757 set_user_preference('grade_report_showonlyactiveenrol', false);
758 $assign = $this->create_instance(array('grade'=>100));
759 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
760 count($assign->list_participants(null, true)));
761
1ecb8044 762 // Non-editing teacher should not see suspended users, even if user preference is set.
e6cc5347
RT
763 $this->setUser($this->teachers[0]);
764 set_user_preference('grade_report_showonlyactiveenrol', false);
765 $assign = $this->create_instance(array('grade'=>100));
766 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
c13ac85d 767
768 // Turn on availability and a group restriction, and check that it doesn't
769 // show users who aren't in the group.
770 $CFG->enableavailability = true;
771 $specialgroup = $this->getDataGenerator()->create_group(
772 array('courseid' => $this->course->id));
773 $assign = $this->create_instance(array('grade' => 100,
774 'availability' => json_encode(\core_availability\tree::get_root_json(
775 array(\availability_group\condition::get_json($specialgroup->id))))));
776 groups_add_member($specialgroup, $this->students[0]);
777 groups_add_member($specialgroup, $this->students[1]);
778 $this->assertEquals(2, count($assign->list_participants(null, true)));
47f48152
DW
779 }
780
1b2f9dc6
RW
781 public function test_get_participant_user_not_exist() {
782 $assign = $this->create_instance(array('grade' => 100));
783 $this->assertNull($assign->get_participant('-1'));
784 }
785
786 public function test_get_participant_not_enrolled() {
787 $assign = $this->create_instance(array('grade' => 100));
788 $user = $this->getDataGenerator()->create_user();
789 $this->assertNull($assign->get_participant($user->id));
790 }
791
792 public function test_get_participant_no_submission() {
793 $assign = $this->create_instance(array('grade' => 100));
794 $student = $this->students[0];
795 $participant = $assign->get_participant($student->id);
796
797 $this->assertEquals($student->id, $participant->id);
798 $this->assertFalse($participant->submitted);
799 $this->assertFalse($participant->requiregrading);
800 }
801
802 public function test_get_participant_with_ungraded_submission() {
803 $assign = $this->create_instance(array('grade' => 100));
804 $student = $this->students[0];
805 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
806
807 $this->setUser($student);
808
809 // Simulate a submission.
810 $data = new stdClass();
811 $data->onlinetext_editor = array(
812 'itemid' => file_get_unused_draft_itemid(),
813 'text' => 'Student submission text',
814 'format' => FORMAT_MOODLE
815 );
816
817 $notices = array();
818 $assign->save_submission($data, $notices);
819
820 $data = new stdClass;
821 $data->userid = $student->id;
822 $assign->submit_for_grading($data, array());
823
824 $participant = $assign->get_participant($student->id);
825
826 $this->assertEquals($student->id, $participant->id);
827 $this->assertTrue($participant->submitted);
828 $this->assertTrue($participant->requiregrading);
829 }
830
831 public function test_get_participant_with_graded_submission() {
832 $assign = $this->create_instance(array('grade' => 100));
833 $student = $this->students[0];
834 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
835
836 $this->setUser($student);
837
838 // Simulate a submission.
839 $data = new stdClass();
840 $data->onlinetext_editor = array(
841 'itemid' => file_get_unused_draft_itemid(),
842 'text' => 'Student submission text',
843 'format' => FORMAT_MOODLE
844 );
845
846 $notices = array();
847 $assign->save_submission($data, $notices);
848
849 $data = new stdClass;
850 $data->userid = $student->id;
851 $assign->submit_for_grading($data, array());
852
853 // This is to make sure the grade happens after the submission because
854 // we have no control over the timemodified values.
74ee9d29 855 $this->waitForSecond();
1b2f9dc6
RW
856 // Grade the submission.
857 $this->setUser($this->teachers[0]);
858
859 $data = new stdClass();
860 $data->grade = '50.0';
861 $assign->testable_apply_grade_to_user($data, $student->id, 0);
862
863 $participant = $assign->get_participant($student->id);
864
865 $this->assertEquals($student->id, $participant->id);
866 $this->assertTrue($participant->submitted);
867 $this->assertFalse($participant->requiregrading);
868 }
869
47f48152 870 public function test_count_teams() {
df211804 871 $this->create_extra_users();
47f48152 872 $this->setUser($this->editingteachers[0]);
2dda9417
DM
873 $assign1 = $this->create_instance(array('teamsubmission' => 1));
874 $this->assertEquals(self::GROUP_COUNT + 1, $assign1->count_teams());
47f48152 875
2dda9417
DM
876 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
877 $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[0]->id, 'groupingid' => $grouping->id));
878 $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[1]->id, 'groupingid' => $grouping->id));
879
e528997a
AH
880 // No active group and non group submissions allowed => 2 groups + the default one.
881 $params = array(
882 'teamsubmission' => 1,
883 'teamsubmissiongroupingid' => $grouping->id,
884 'preventsubmissionnotingroup' => false
885 );
886 $assign2 = $this->create_instance($params);
2dda9417
DM
887 $this->assertEquals(3, $assign2->count_teams());
888
889 // An active group => Just the selected one.
890 $this->assertEquals(1, $assign2->count_teams($this->groups[0]->id));
e528997a
AH
891
892 // No active group and non group submissions allowed => 2 groups + no default one.
893 $params = array('teamsubmission' => 1, 'teamsubmissiongroupingid' => $grouping->id, 'preventsubmissionnotingroup' => true);
894 $assign3 = $this->create_instance($params);
895 $this->assertEquals(2, $assign3->count_teams());
896
897 $assign4 = $this->create_instance(array('teamsubmission' => 1, 'preventsubmissionnotingroup' => true));
898 $this->assertEquals(self::GROUP_COUNT, $assign4->count_teams());
47f48152
DW
899 }
900
e2d2d8a1 901 public function test_submit_to_default_group() {
2dda9417 902 global $DB, $SESSION;
e2d2d8a1
DW
903
904 $this->preventResetByRollback();
905 $sink = $this->redirectMessages();
906
907 $this->setUser($this->editingteachers[0]);
908 $params = array('teamsubmission' => 1,
909 'assignsubmission_onlinetext_enabled' => 1,
2dda9417
DM
910 'submissiondrafts' => 0,
911 'groupmode' => VISIBLEGROUPS);
e2d2d8a1
DW
912 $assign = $this->create_instance($params);
913
914 $newstudent = $this->getDataGenerator()->create_user();
915 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
916 $this->getDataGenerator()->enrol_user($newstudent->id,
917 $this->course->id,
918 $studentrole->id);
919 $this->setUser($newstudent);
920 $data = new stdClass();
921 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
922 'text'=>'Submission text',
923 'format'=>FORMAT_MOODLE);
924 $notices = array();
925
926 $group = $assign->get_submission_group($newstudent->id);
927 $this->assertFalse($group, 'New student is in default group');
928 $assign->save_submission($data, $notices);
929 $this->assertEmpty($notices, 'No errors on save submission');
930
2dda9417 931 // Set active groups to all groups.
4ceed4df 932 $this->setUser($this->editingteachers[0]);
2dda9417
DM
933 $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
934 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
935
936 // Set an active group.
937 $anothergroup = $this->groups[0];
938 $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
939 $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
940
e2d2d8a1
DW
941 $sink->close();
942 }
943
47f48152 944 public function test_count_submissions() {
2dda9417
DM
945 global $SESSION;
946
df211804 947 $this->create_extra_users();
47f48152 948 $this->setUser($this->editingteachers[0]);
2dda9417 949 $assign1 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
47f48152
DW
950
951 // Simulate a submission.
a5c793c3 952 $this->setUser($this->extrastudents[0]);
2dda9417 953 $submission = $assign1->get_user_submission($this->extrastudents[0]->id, true);
9e3eee67 954 $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
2dda9417 955 $assign1->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
956 // Leave this one as DRAFT.
957 $data = new stdClass();
958 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
959 'text'=>'Submission text',
960 'format'=>FORMAT_MOODLE);
2dda9417 961 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
962 $plugin->save($submission, $data);
963
964 // Simulate adding a grade.
965 $this->setUser($this->teachers[0]);
966 $data = new stdClass();
967 $data->grade = '50.0';
2dda9417 968 $assign1->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
47f48152
DW
969
970 // Simulate a submission.
a5c793c3 971 $this->setUser($this->extrastudents[1]);
2dda9417 972 $submission = $assign1->get_user_submission($this->extrastudents[1]->id, true);
47f48152 973 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 974 $assign1->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
47f48152
DW
975 $data = new stdClass();
976 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
977 'text'=>'Submission text',
978 'format'=>FORMAT_MOODLE);
2dda9417 979 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
980 $plugin->save($submission, $data);
981
982 // Simulate a submission.
a5c793c3 983 $this->setUser($this->extrastudents[2]);
2dda9417 984 $submission = $assign1->get_user_submission($this->extrastudents[2]->id, true);
47f48152 985 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 986 $assign1->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
47f48152
DW
987 $data = new stdClass();
988 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
989 'text'=>'Submission text',
990 'format'=>FORMAT_MOODLE);
2dda9417 991 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
992 $plugin->save($submission, $data);
993
994 // Simulate a submission.
a5c793c3 995 $this->setUser($this->extrastudents[3]);
2dda9417 996 $submission = $assign1->get_user_submission($this->extrastudents[3]->id, true);
47f48152 997 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 998 $assign1->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
47f48152
DW
999 $data = new stdClass();
1000 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1001 'text'=>'Submission text',
1002 'format'=>FORMAT_MOODLE);
2dda9417 1003 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
1004 $plugin->save($submission, $data);
1005
e6cc5347
RT
1006 // Simulate a submission for suspended user, this will never be counted.
1007 $this->setUser($this->extrastudents[3]);
2dda9417 1008 $submission = $assign1->get_user_submission($this->extrasuspendedstudents[0]->id, true);
e6cc5347 1009 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 1010 $assign1->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
e6cc5347
RT
1011 $data = new stdClass();
1012 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1013 'text'=>'Submission text',
1014 'format'=>FORMAT_MOODLE);
2dda9417 1015 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
e6cc5347
RT
1016 $plugin->save($submission, $data);
1017
fb6bae3e 1018 // Wait 1 second so the submission and grade do not have the same timemodified.
74ee9d29 1019 $this->waitForSecond();
47f48152 1020 // Simulate adding a grade.
50c734e8 1021 $this->setUser($this->editingteachers[0]);
47f48152
DW
1022 $data = new stdClass();
1023 $data->grade = '50.0';
2dda9417
DM
1024 $assign1->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
1025 $assign1->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
47f48152 1026
ab14ab74
FM
1027 // Create a new submission with status NEW.
1028 $this->setUser($this->extrastudents[4]);
2dda9417
DM
1029 $submission = $assign1->get_user_submission($this->extrastudents[4]->id, true);
1030
1031 $this->assertEquals(2, $assign1->count_grades());
1032 $this->assertEquals(4, $assign1->count_submissions());
1033 $this->assertEquals(5, $assign1->count_submissions(true));
1034 $this->assertEquals(2, $assign1->count_submissions_need_grading());
1035 $this->assertEquals(3, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1036 $this->assertEquals(1, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
1037
1038 // Groups.
1039 $assign2 = $this->create_instance(array(
1040 'assignsubmission_onlinetext_enabled' => 1,
1041 'groupmode' => VISIBLEGROUPS
1042 ));
1043
1044 $this->setUser($this->extrastudents[1]);
1045 $submission = $assign2->get_user_submission($this->extrastudents[1]->id, true);
1046 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1047 $assign2->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
1048 $data = new stdClass();
1049 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1050 'text' => 'Submission text',
1051 'format' => FORMAT_MOODLE);
1052 $plugin = $assign2->get_submission_plugin_by_type('onlinetext');
1053 $plugin->save($submission, $data);
1054
1055 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1056
1057 // Set active groups to all groups.
4ceed4df 1058 $this->setUser($this->editingteachers[0]);
2dda9417
DM
1059 $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
1060 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1061
1062 // Set the user group.
1063 $studentgroups = groups_get_user_groups($this->course->id, $this->extrastudents[1]->id);
1064 $this->assertEquals(1, count($studentgroups));
1065 $studentgroup = array_pop($studentgroups);
1066 $SESSION->activegroup[$this->course->id]['aag'][0] = $studentgroup[0];
1067 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1068
1069 // Set another group.
1070 $anothergroup = $this->groups[0];
1071 $this->assertNotEquals($anothergroup->id, $studentgroup[0]);
1072 $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
1073 $this->assertEquals(0, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
47f48152
DW
1074 }
1075
ab14ab74
FM
1076 public function test_count_submissions_for_groups() {
1077 $this->create_extra_users();
1078 $groupid = null;
1079 $this->setUser($this->editingteachers[0]);
1080 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1, 'teamsubmission' => 1));
1081
1082 // Simulate a submission.
1083 $this->setUser($this->extrastudents[0]);
1084 $submission = $assign->get_group_submission($this->extrastudents[0]->id, $groupid, true);
1085 $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
1086 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
1087 // Leave this one as DRAFT.
1088 $data = new stdClass();
1089 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1090 'text' => 'Submission text',
1091 'format' => FORMAT_MOODLE);
1092 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1093 $plugin->save($submission, $data);
1094
1095 // Simulate adding a grade.
1096 $this->setUser($this->teachers[0]);
1097 $data = new stdClass();
1098 $data->grade = '50.0';
1099 $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
1100
1101 // Simulate a submission.
1102 $this->setUser($this->extrastudents[1]);
1103 $submission = $assign->get_group_submission($this->extrastudents[1]->id, $groupid, true);
1104 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1105 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
1106 $data = new stdClass();
1107 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1108 'text' => 'Submission text',
1109 'format' => FORMAT_MOODLE);
1110 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1111 $plugin->save($submission, $data);
1112
1113 // Simulate a submission.
1114 $this->setUser($this->extrastudents[2]);
1115 $submission = $assign->get_group_submission($this->extrastudents[2]->id, $groupid, true);
1116 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1117 $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
1118 $data = new stdClass();
1119 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1120 'text' => 'Submission text',
1121 'format' => FORMAT_MOODLE);
1122 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1123 $plugin->save($submission, $data);
1124
1125 // Simulate a submission.
1126 $this->setUser($this->extrastudents[3]);
1127 $submission = $assign->get_group_submission($this->extrastudents[3]->id, $groupid, true);
1128 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1129 $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
1130 $data = new stdClass();
1131 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1132 'text' => 'Submission text',
1133 'format' => FORMAT_MOODLE);
1134 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1135 $plugin->save($submission, $data);
1136
1137 // Simulate adding a grade.
50c734e8 1138 $this->setUser($this->editingteachers[0]);
ab14ab74
FM
1139 $data = new stdClass();
1140 $data->grade = '50.0';
1141 $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
1142 $assign->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
1143
1144 // Create a new submission with status NEW.
1145 $this->setUser($this->extrastudents[4]);
1146 $submission = $assign->get_group_submission($this->extrastudents[4]->id, $groupid, true);
1147
1148 $this->assertEquals(2, $assign->count_grades());
1149 $this->assertEquals(4, $assign->count_submissions());
1150 $this->assertEquals(5, $assign->count_submissions(true));
1151 $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1152 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
1153 }
1154
47f48152 1155 public function test_get_grading_userid_list() {
df211804 1156 $this->create_extra_users();
47f48152
DW
1157 $this->setUser($this->editingteachers[0]);
1158 $assign = $this->create_instance();
1159
1160 $users = $assign->testable_get_grading_userid_list();
a5c793c3 1161 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
e6cc5347
RT
1162
1163 $this->setUser($this->editingteachers[0]);
1164 set_user_preference('grade_report_showonlyactiveenrol', false);
1165 $assign = $this->create_instance();
1166
1167 $users = $assign->testable_get_grading_userid_list();
1168 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
47f48152
DW
1169 }
1170
1171 public function test_cron() {
1172 // First run cron so there are no messages waiting to be sent (from other tests).
1173 cron_setup_user();
1174 assign::cron();
1175
1176 // Now create an assignment and add some feedback.
1177 $this->setUser($this->editingteachers[0]);
8e1266bf 1178 $assign = $this->create_instance(array('sendstudentnotifications'=>1));
47f48152
DW
1179
1180 // Simulate adding a grade.
1181 $this->setUser($this->teachers[0]);
1182 $data = new stdClass();
1183 $data->grade = '50.0';
df211804 1184 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
4d2bd673 1185 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
47f48152 1186
f7dc9871
DW
1187 $data->sendstudentnotifications = false;
1188 $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
1189
47f48152
DW
1190 // Now run cron and see that one message was sent.
1191 $this->preventResetByRollback();
1192 $sink = $this->redirectMessages();
1193 cron_setup_user();
4d2bd673 1194 $this->expectOutputRegex('/Done processing 2 assignment submissions/');
47f48152
DW
1195 assign::cron();
1196
1197 $messages = $sink->get_messages();
f7dc9871 1198 // The sent count should be 2, because the 3rd one was marked as do not send notifications.
4d2bd673 1199 $this->assertEquals(2, count($messages));
47f48152
DW
1200 $this->assertEquals(1, $messages[0]->notification);
1201 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
a4b10a52
ZD
1202
1203 // Regrading a grade causes a notification to the user.
1204 $data->sendstudentnotifications = true;
1205 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1206 assign::cron();
1207 $messages = $sink->get_messages();
1208 $this->assertEquals(3, count($messages));
47f48152
DW
1209 }
1210
70cfc878
JF
1211 /**
1212 * Test delivery of grade notifications as controlled by marking workflow.
1213 */
1214 public function test_markingworkflow_cron() {
1215 // First run cron so there are no messages waiting to be sent (from other tests).
1216 cron_setup_user();
1217 assign::cron();
1218
1219 // Now create an assignment with marking workflow enabled.
1220 $this->setUser($this->editingteachers[0]);
1221 $assign = $this->create_instance(array('sendstudentnotifications' => 1, 'markingworkflow' => 1));
1222
1223 // Simulate adding a grade.
1224 $this->setUser($this->teachers[0]);
1225 $data = new stdClass();
1226 $data->grade = '50.0';
1227
1228 // This student will not receive notification.
1229 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
1230 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1231
1232 // This student will receive notification.
1233 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
1234 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
1235
1236 // Now run cron and see that one message was sent.
1237 $this->preventResetByRollback();
1238 $sink = $this->redirectMessages();
1239 cron_setup_user();
1240 $this->expectOutputRegex('/Done processing 1 assignment submissions/');
1241 assign::cron();
1242
1243 $messages = $sink->get_messages();
1244 $this->assertEquals(1, count($messages));
1245 $this->assertEquals($messages[0]->useridto, $this->students[1]->id);
1246 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
1247 }
1248
47f48152
DW
1249 public function test_is_graded() {
1250 $this->setUser($this->editingteachers[0]);
1251 $assign = $this->create_instance();
1252
1253 // Simulate adding a grade.
1254 $this->setUser($this->teachers[0]);
1255 $data = new stdClass();
1256 $data->grade = '50.0';
df211804 1257 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
1258
1259 $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
1260 $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
1261 }
1262
4a47008c
DW
1263 public function test_can_grade() {
1264 global $DB;
1265
1266 $this->setUser($this->editingteachers[0]);
1267 $assign = $this->create_instance();
1268
1269 $this->setUser($this->students[0]);
1270 $this->assertEquals(false, $assign->can_grade());
1271 $this->setUser($this->editingteachers[0]);
1272 $this->assertEquals(true, $assign->can_grade());
1273 $this->setUser($this->teachers[0]);
1274 $this->assertEquals(true, $assign->can_grade());
1275
1276 // Test the viewgrades capability - without mod/assign:grade.
1277 $this->setUser($this->students[0]);
1278 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1279 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
1280 $this->assertEquals(false, $assign->can_grade());
1281 }
1282
47f48152 1283 public function test_can_view_submission() {
4a47008c
DW
1284 global $DB;
1285
e6cc5347 1286 $this->create_extra_users();
47f48152
DW
1287 $this->setUser($this->editingteachers[0]);
1288 $assign = $this->create_instance();
1289
1290 $this->setUser($this->students[0]);
1291 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1292 $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
1293 $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
1294 $this->setUser($this->teachers[0]);
1295 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1296 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1297 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 1298 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
1299 $this->setUser($this->editingteachers[0]);
1300 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1301 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1302 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 1303 $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
4a47008c
DW
1304
1305 // Test the viewgrades capability - without mod/assign:grade.
1306 $this->setUser($this->students[0]);
1307 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1308 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
1309 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1310 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1311 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
1312 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
1313 }
1314
1315
1316 public function test_update_submission() {
df211804 1317 $this->create_extra_users();
47f48152
DW
1318 $this->setUser($this->editingteachers[0]);
1319 $assign = $this->create_instance();
1320
a5c793c3 1321 $this->setUser($this->extrastudents[0]);
47f48152 1322 $now = time();
a5c793c3
DW
1323 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
1324 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
1325
1326 $this->setUser($this->teachers[0]);
1327 // Verify the gradebook update.
1328 $gradinginfo = grade_get_grades($this->course->id,
1329 'mod',
1330 'assign',
1331 $assign->get_instance()->id,
a5c793c3 1332 $this->extrastudents[0]->id);
47f48152 1333
a5c793c3
DW
1334 $this->assertEquals($this->extrastudents[0]->id,
1335 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
1336
1337 // Now verify group assignments.
1338 $this->setUser($this->editingteachers[0]);
1339 $assign = $this->create_instance(array('teamsubmission'=>1));
1340
a5c793c3 1341 $this->setUser($this->extrastudents[0]);
47f48152 1342 $now = time();
a5c793c3
DW
1343 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1344 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
47f48152 1345
e6cc5347 1346 // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
47f48152
DW
1347
1348 $this->setUser($this->editingteachers[0]);
1349 $gradinginfo = grade_get_grades($this->course->id,
1350 'mod',
1351 'assign',
1352 $assign->get_instance()->id,
a5c793c3 1353 $this->extrastudents[0]->id);
47f48152 1354
a5c793c3
DW
1355 $this->assertEquals($this->extrastudents[0]->id,
1356 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
1357
1358 $gradinginfo = grade_get_grades($this->course->id,
1359 'mod',
1360 'assign',
1361 $assign->get_instance()->id,
a5c793c3 1362 $this->extrastudents[self::GROUP_COUNT]->id);
47f48152 1363
a5c793c3
DW
1364 $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
1365 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
47f48152 1366
e6cc5347
RT
1367 $gradinginfo = grade_get_grades($this->course->id,
1368 'mod',
1369 'assign',
1370 $assign->get_instance()->id,
1371 $this->extrasuspendedstudents[0]->id);
1372 $this->assertEquals($this->extrasuspendedstudents[0]->id,
1373 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
1374
1375 // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
1376 $this->setUser($this->editingteachers[0]);
1377 $assign = $this->create_instance(array('teamsubmission'=>1));
1378
1379 $this->setUser($this->extrastudents[1]);
1380 $now = time();
1381 $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
1382 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
1383
1384 $this->setUser($this->teachers[0]);
1385 $gradinginfo = grade_get_grades($this->course->id,
1386 'mod',
1387 'assign',
1388 $assign->get_instance()->id,
1389 $this->extrastudents[1]->id);
1390
1391 $this->assertEquals($this->extrastudents[1]->id,
1392 $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
1393
1394 $gradinginfo = grade_get_grades($this->course->id,
1395 'mod',
1396 'assign',
1397 $assign->get_instance()->id,
1398 $this->extrastudents[self::GROUP_COUNT+1]->id);
1399
1400 $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
1401 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
1402
1403 $gradinginfo = grade_get_grades($this->course->id,
1404 'mod',
1405 'assign',
1406 $assign->get_instance()->id,
1407 $this->extrasuspendedstudents[1]->id);
1408 $this->assertEquals($this->extrasuspendedstudents[1]->id,
1409 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
1410
47f48152
DW
1411 // Now verify blind marking.
1412 $this->setUser($this->editingteachers[0]);
1413 $assign = $this->create_instance(array('blindmarking'=>1));
1414
a5c793c3 1415 $this->setUser($this->extrastudents[0]);
47f48152 1416 $now = time();
a5c793c3
DW
1417 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
1418 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
1419
1420 $this->setUser($this->editingteachers[0]);
1421 $gradinginfo = grade_get_grades($this->course->id,
1422 'mod',
1423 'assign',
1424 $assign->get_instance()->id,
a5c793c3 1425 $this->extrastudents[0]->id);
47f48152 1426
a5c793c3 1427 $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
47f48152
DW
1428 }
1429
79397b56 1430 public function test_group_submissions_submit_for_marking_requireallteammemberssubmit() {
2bd27878
DW
1431 global $PAGE;
1432
1433 $this->create_extra_users();
1434 // Now verify group assignments.
1435 $this->setUser($this->editingteachers[0]);
1436 $assign = $this->create_instance(array('teamsubmission'=>1,
1437 'assignsubmission_onlinetext_enabled'=>1,
1438 'submissiondrafts'=>1,
1439 'requireallteammemberssubmit'=>1));
1440 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1441
2bd27878 1442 // Add a submission.
79397b56 1443 $this->setUser($this->extrastudents[0]);
2bd27878
DW
1444 $data = new stdClass();
1445 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1446 'text'=>'Submission text',
1447 'format'=>FORMAT_MOODLE);
1448
1449 $notices = array();
1450 $assign->save_submission($data, $notices);
1451
1452 // Check we can see the submit button.
1453 $output = $assign->view_student_summary($this->extrastudents[0], true);
1454 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1455
1456 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1457 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1458 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1459
1460 // Check that the student does not see "Submit" button.
1461 $output = $assign->view_student_summary($this->extrastudents[0], true);
1462 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1463
1464 // Change to another user in the same group.
1465 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1466 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1467 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1468
1469 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1470 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1471 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1472 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1473 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1474 }
1475
79397b56
DB
1476 public function test_group_submissions_submit_for_marking() {
1477 global $PAGE;
1478
1479 $this->create_extra_users();
1480 // Now verify group assignments.
1481 $this->setUser($this->editingteachers[0]);
a0f8db77 1482 $time = time();
79397b56
DB
1483 $assign = $this->create_instance(array('teamsubmission'=>1,
1484 'assignsubmission_onlinetext_enabled'=>1,
1485 'submissiondrafts'=>1,
1486 'requireallteammemberssubmit'=>0,
a0f8db77 1487 'duedate' => $time - 2*24*60*60));
79397b56
DB
1488 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1489
1490 $this->setUser($this->extrastudents[0]);
1491 // Add a submission.
1492 $data = new stdClass();
1493 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1494 'text'=>'Submission text',
1495 'format'=>FORMAT_MOODLE);
1496
1497 $notices = array();
1498 $assign->save_submission($data, $notices);
1499
1500 // Check we can see the submit button.
1501 $output = $assign->view_student_summary($this->extrastudents[0], true);
1502 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1503 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1504 $difftime = time() - $time;
1505 $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1506
1507 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1508 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1509 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1510
1511 // Check that the student does not see "Submit" button.
1512 $output = $assign->view_student_summary($this->extrastudents[0], true);
1513 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1514
1515 // Change to another user in the same group.
1516 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1517 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1518 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1519
1520 // Check that time remaining is not overdue.
1521 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1522 $difftime = time() - $time;
1523 $this->assertContains(get_string('submittedlate', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1524
1525 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1526 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1527 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1528 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1529 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1530 }
1531
47f48152
DW
1532 public function test_submissions_open() {
1533 $this->setUser($this->editingteachers[0]);
1534
1535 $now = time();
1536 $tomorrow = $now + 24*60*60;
1537 $oneweek = $now + 7*24*60*60;
1538 $yesterday = $now - 24*60*60;
1539
1540 $assign = $this->create_instance();
1541 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1542
1543 $assign = $this->create_instance(array('duedate'=>$tomorrow));
1544 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1545
1546 $assign = $this->create_instance(array('duedate'=>$yesterday));
1547 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1548
1549 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
1550 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1551
1552 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
1553 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1554
1555 $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
1556 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1557
1558 $assign = $this->create_instance(array('submissiondrafts'=>1));
1559 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1560
1561 $this->setUser($this->students[0]);
1562 $now = time();
1563 $submission = $assign->get_user_submission($this->students[0]->id, true);
1564 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1565 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1566 $this->setUser($this->editingteachers[0]);
1567 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1568 }
1569
1570 public function test_get_graders() {
df211804 1571 $this->create_extra_users();
47f48152 1572 $this->setUser($this->editingteachers[0]);
47f48152 1573
f268fb5d
DW
1574 // Create an assignment with no groups.
1575 $assign = $this->create_instance();
a5c793c3
DW
1576 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1577 self::DEFAULT_EDITING_TEACHER_COUNT +
1578 self::EXTRA_TEACHER_COUNT +
1579 self::EXTRA_EDITING_TEACHER_COUNT,
1580 $assign->testable_get_graders($this->students[0]->id));
47f48152 1581
47f48152 1582 // Force create an assignment with SEPARATEGROUPS.
f268fb5d
DW
1583 $data = new stdClass();
1584 $data->courseid = $this->course->id;
1585 $data->name = 'Grouping';
1586 $groupingid = groups_create_grouping($data);
1587 groups_assign_grouping($groupingid, $this->groups[0]->id);
1588 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
47f48152
DW
1589
1590 $this->setUser($this->students[1]);
a5c793c3 1591 $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
f268fb5d
DW
1592 // Note the second student is in a group that is not in the grouping.
1593 // This means that we get all graders that are not in a group in the grouping.
1594 $this->assertCount(10, $assign->testable_get_graders($this->students[1]->id));
47f48152
DW
1595 }
1596
83360c8d
S
1597 public function test_get_notified_users() {
1598 global $CFG, $DB;
1599
1600 $capability = 'mod/assign:receivegradernotifications';
1601 $coursecontext = context_course::instance($this->course->id);
1602 $role = $DB->get_record('role', array('shortname' => 'teacher'));
1603
1604 $this->create_extra_users();
1605 $this->setUser($this->editingteachers[0]);
1606
1607 // Create an assignment with no groups.
1608 $assign = $this->create_instance();
1609
1610 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1611 self::DEFAULT_EDITING_TEACHER_COUNT +
1612 self::EXTRA_TEACHER_COUNT +
1613 self::EXTRA_EDITING_TEACHER_COUNT,
1614 $assign->testable_get_notifiable_users($this->students[0]->id));
1615
1616 // Change nonediting teachers role to not receive grader notifications.
1617 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1618
1619 $this->assertCount(self::DEFAULT_EDITING_TEACHER_COUNT +
1620 self::EXTRA_EDITING_TEACHER_COUNT,
1621 $assign->testable_get_notifiable_users($this->students[0]->id));
1622
1623 // Reset nonediting teachers role to default.
1624 unassign_capability($capability, $role->id, $coursecontext);
1625
1626 // Force create an assignment with SEPARATEGROUPS.
1627 $data = new stdClass();
1628 $data->courseid = $this->course->id;
1629 $data->name = 'Grouping';
1630 $groupingid = groups_create_grouping($data);
1631 groups_assign_grouping($groupingid, $this->groups[0]->id);
1632 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
1633
1634 $this->setUser($this->students[1]);
1635 $this->assertCount(4, $assign->testable_get_notifiable_users($this->students[0]->id));
1636 // Note the second student is in a group that is not in the grouping.
1637 // This means that we get all graders that are not in a group in the grouping.
1638 $this->assertCount(10, $assign->testable_get_notifiable_users($this->students[1]->id));
1639
1640 // Change nonediting teachers role to not receive grader notifications.
1641 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1642
1643 $this->assertCount(2, $assign->testable_get_notifiable_users($this->students[0]->id));
1644 // Note the second student is in a group that is not in the grouping.
1645 // This means that we get all graders that are not in a group in the grouping.
1646 $this->assertCount(5, $assign->testable_get_notifiable_users($this->students[1]->id));
1647 }
1648
20b7dcfc
DW
1649 public function test_group_members_only() {
1650 global $CFG;
1651
1652 $this->setAdminUser();
1653 $this->create_extra_users();
c13ac85d 1654 $CFG->enableavailability = true;
20b7dcfc
DW
1655 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
1656 groups_assign_grouping($grouping->id, $this->groups[0]->id);
1657
1658 // Force create an assignment with SEPARATEGROUPS.
1659 $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
c13ac85d 1660 array('availability' => json_encode(\core_availability\tree::get_root_json(array(
1661 \availability_grouping\condition::get_json()))),
1662 'groupingid' => $grouping->id));
20b7dcfc
DW
1663
1664 $cm = get_coursemodule_from_instance('assign', $instance->id);
1665 $context = context_module::instance($cm->id);
1666 $assign = new testable_assign($context, $cm, $this->course);
1667
1668 $this->setUser($this->teachers[0]);
8270f0d0 1669 get_fast_modinfo($this->course, 0, true);
20b7dcfc
DW
1670 $this->assertCount(5, $assign->list_participants(0, true));
1671
1672 }
1673
47f48152
DW
1674 public function test_get_uniqueid_for_user() {
1675 $this->setUser($this->editingteachers[0]);
1676 $assign = $this->create_instance();
1677
1678 foreach ($this->students as $student) {
1679 $uniqueid = $assign->get_uniqueid_for_user($student->id);
1680 $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
1681 }
1682 }
1683
46692c3a 1684 public function test_show_student_summary() {
c2114099 1685 global $CFG, $PAGE;
46692c3a
DW
1686
1687 $this->setUser($this->editingteachers[0]);
1688 $assign = $this->create_instance();
c2114099 1689 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
46692c3a
DW
1690
1691 // No feedback should be available because this student has not been graded.
1692 $this->setUser($this->students[0]);
1693 $output = $assign->view_student_summary($this->students[0], true);
1694 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
1695 // Simulate adding a grade.
1696 $this->setUser($this->teachers[0]);
1697 $data = new stdClass();
1698 $data->grade = '50.0';
df211804 1699 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
46692c3a 1700
b0da618b 1701 // Now we should see the feedback.
46692c3a
DW
1702 $this->setUser($this->students[0]);
1703 $output = $assign->view_student_summary($this->students[0], true);
1704 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
1705
1706 // Now hide the grade in gradebook.
1707 $this->setUser($this->teachers[0]);
1708 require_once($CFG->libdir.'/gradelib.php');
1709 $gradeitem = new grade_item(array(
1710 'itemtype' => 'mod',
1711 'itemmodule' => 'assign',
1712 'iteminstance' => $assign->get_instance()->id,
1713 'courseid' => $this->course->id));
1714
1715 $gradeitem->set_hidden(1, false);
1716
1717 // No feedback should be available because the grade is hidden.
1718 $this->setUser($this->students[0]);
1719 $output = $assign->view_student_summary($this->students[0], true);
1720 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
1721
b0da618b 1722 // Do the same but add feedback.
46692c3a
DW
1723 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
1724
1725 $this->setUser($this->teachers[0]);
1726 $grade = $assign->get_user_grade($this->students[0]->id, true);
1727 $data = new stdClass();
1728 $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
1729 'format'=>FORMAT_MOODLE);
1730 $plugin = $assign->get_feedback_plugin_by_type('comments');
1731 $plugin->save($grade, $data);
1732
b0da618b 1733 // Should have feedback but no grade.
46692c3a
DW
1734 $this->setUser($this->students[0]);
1735 $output = $assign->view_student_summary($this->students[0], true);
ea698284 1736 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
46692c3a
DW
1737 $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
1738 $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
45aac51a 1739
ea698284
AD
1740 // Now hide the grade in gradebook.
1741 $this->setUser($this->teachers[0]);
1742 $gradeitem = new grade_item(array(
1743 'itemtype' => 'mod',
1744 'itemmodule' => 'assign',
1745 'iteminstance' => $assign->get_instance()->id,
1746 'courseid' => $this->course->id));
1747
1748 $gradeitem->set_hidden(1, false);
1749
1750 // No feedback should be available because the grade is hidden.
1751 $this->setUser($this->students[0]);
1752 $output = $assign->view_student_summary($this->students[0], true);
1753 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
46692c3a
DW
1754 }
1755
df211804
DW
1756 public function test_attempt_reopen_method_manual() {
1757 global $PAGE;
1758
1759 $this->setUser($this->editingteachers[0]);
1760 $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
1761 'maxattempts'=>3,
1762 'submissiondrafts'=>1,
1763 'assignsubmission_onlinetext_enabled'=>1));
1764 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1765
1766 // Student should be able to see an add submission button.
1767 $this->setUser($this->students[0]);
1768 $output = $assign->view_student_summary($this->students[0], true);
1769 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1770
1771 // Add a submission.
1772 $now = time();
1773 $submission = $assign->get_user_submission($this->students[0]->id, true);
1774 $data = new stdClass();
1775 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1776 'text'=>'Submission text',
1777 'format'=>FORMAT_MOODLE);
1778 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1779 $plugin->save($submission, $data);
1780
1781 // And now submit it for marking.
1782 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1783 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1784
1785 // Verify the student cannot make changes to the submission.
1786 $output = $assign->view_student_summary($this->students[0], true);
1787 $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1788
1789 // Mark the submission.
1790 $this->setUser($this->teachers[0]);
1791 $data = new stdClass();
1792 $data->grade = '50.0';
1793 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1794
1795 // Check the student can see the grade.
1796 $this->setUser($this->students[0]);
1797 $output = $assign->view_student_summary($this->students[0], true);
1798 $this->assertNotEquals(false, strpos($output, '50.0'));
1799
1800 // Allow the student another attempt.
1801 $this->teachers[0]->ignoresesskey = true;
1802 $this->setUser($this->teachers[0]);
1803 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1804 $this->assertEquals(true, $result);
1805
1806 // Check that the previous attempt is now in the submission history table.
1807 $this->setUser($this->students[0]);
1808 $output = $assign->view_student_summary($this->students[0], true);
1809 // Need a better check.
1810 $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
1811
1812 // Check that the student now has a button for Add a new attempt".
1813 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1814 // Check that the student now does not have a button for Submit.
1815 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
1816
1817 // Check that the student now has a submission history.
1818 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
1819
1820 $this->setUser($this->teachers[0]);
1821 // Check that the grading table loads correctly and contains this user.
1822 // This is also testing that we do not get duplicate rows in the grading table.
1823 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1824 $output = $assign->get_renderer()->render($gradingtable);
1825 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1826
1827 // Should be 1 not 2.
1828 $this->assertEquals(1, $assign->count_submissions());
1829 $this->assertEquals(1, $assign->count_submissions_with_status('reopened'));
1830 $this->assertEquals(0, $assign->count_submissions_need_grading());
1831 $this->assertEquals(1, $assign->count_grades());
1832
1833 // Change max attempts to unlimited.
1834 $formdata = clone($assign->get_instance());
1835 $formdata->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS;
1836 $formdata->instance = $formdata->id;
1837 $assign->update_instance($formdata);
1838
9e3eee67
DW
1839 // Mark the submission again.
1840 $data = new stdClass();
1841 $data->grade = '60.0';
1842 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1843
1844 // Check the grade exists.
1845 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
1846 $this->assertEquals(60, (int)$grades[$this->students[0]->id]->rawgrade);
1847
1848 // Check we can reopen still.
df211804
DW
1849 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1850 $this->assertEquals(true, $result);
1851
9e3eee67 1852 // Should no longer have a grade because there is no grade for the latest attempt.
df211804 1853 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
9e3eee67 1854 $this->assertEmpty($grades);
df211804 1855
df211804 1856 }
46692c3a 1857
e77bacab
MP
1858 /**
1859 * Test reopen behavior when in "Reopen until pass" mode.
1860 */
1861 public function test_attempt_reopen_method_untilpass() {
1862 global $PAGE;
1863
1864 $this->setUser($this->editingteachers[0]);
1865 $assign = $this->create_instance(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
1866 'maxattempts' => 3,
1867 'submissiondrafts' => 1,
1868 'assignsubmission_onlinetext_enabled' => 1));
1869 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1870
1871 // Set grade to pass to 80.
1872 $gradeitem = $assign->get_grade_item();
1873 $gradeitem->gradepass = '80.0';
1874 $gradeitem->update();
1875
1876 // Student should be able to see an add submission button.
1877 $this->setUser($this->students[0]);
1878 $output = $assign->view_student_summary($this->students[0], true);
1879 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1880
1881 // Add a submission.
1882 $now = time();
1883 $submission = $assign->get_user_submission($this->students[0]->id, true);
1884 $data = new stdClass();
1885 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1886 'text' => 'Submission text',
1887 'format' => FORMAT_MOODLE);
1888 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1889 $plugin->save($submission, $data);
1890
1891 // And now submit it for marking.
1892 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1893 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1894
1895 // Verify the student cannot make a new attempt.
1896 $output = $assign->view_student_summary($this->students[0], true);
1897 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1898
1899 // Mark the submission as non-passing.
1900 $this->setUser($this->teachers[0]);
1901 $data = new stdClass();
1902 $data->grade = '50.0';
1903 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1904
1905 // Check the student can see the grade.
1906 $this->setUser($this->students[0]);
1907 $output = $assign->view_student_summary($this->students[0], true);
1908 $this->assertNotEquals(false, strpos($output, '50.0'));
1909
1910 // Check that the student now has a button for Add a new attempt.
1911 $output = $assign->view_student_summary($this->students[0], true);
1912 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1913
1914 // Check that the student now does not have a button for Submit.
1915 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
1916
1917 // Check that the student now has a submission history.
1918 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
1919
1920 // Add a second submission.
1921 $now = time();
1922 $submission = $assign->get_user_submission($this->students[0]->id, true, 1);
1923 $data = new stdClass();
1924 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1925 'text' => 'Submission text',
1926 'format' => FORMAT_MOODLE);
1927 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1928 $plugin->save($submission, $data);
1929
1930 // And now submit it for marking.
1931 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1932 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1933
1934 // Mark the submission as passing.
1935 $this->setUser($this->teachers[0]);
1936 $data = new stdClass();
1937 $data->grade = '80.0';
1938 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1939
1940 // Check that the student does not have a button for Add a new attempt.
1941 $this->setUser($this->students[0]);
1942 $output = $assign->view_student_summary($this->students[0], true);
1943 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1944
1945 // Re-mark the submission as not passing.
1946 $this->setUser($this->teachers[0]);
1947 $data = new stdClass();
1948 $data->grade = '50.0';
1949 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1950
1951 // Check that the student now has a button for Add a new attempt.
1952 $this->setUser($this->students[0]);
1953 $output = $assign->view_student_summary($this->students[0], true);
1954 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1955
1956 // Add a submission as a second student.
1957 $this->setUser($this->students[1]);
1958 $now = time();
1959 $submission = $assign->get_user_submission($this->students[1]->id, true);
1960 $data = new stdClass();
1961 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1962 'text' => 'Submission text',
1963 'format' => FORMAT_MOODLE);
1964 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1965 $plugin->save($submission, $data);
1966
1967 // And now submit it for marking.
1968 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1969 $assign->testable_update_submission($submission, $this->students[1]->id, true, false);
1970
1971 // Mark the submission as passing.
1972 $this->setUser($this->teachers[0]);
1973 $data = new stdClass();
1974 $data->grade = '100.0';
1975 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
1976
1977 // Check the student can see the grade.
1978 $this->setUser($this->students[1]);
1979 $output = $assign->view_student_summary($this->students[1], true);
1980 $this->assertNotEquals(false, strpos($output, '100.0'));
1981
1982 // Check that the student does not have a button for Add a new attempt.
1983 $output = $assign->view_student_summary($this->students[1], true);
1984 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1985
1986 // Set grade to pass to 0, so that no attempts should reopen.
1987 $gradeitem = $assign->get_grade_item();
1988 $gradeitem->gradepass = '0';
1989 $gradeitem->update();
1990
1991 // Add another submission.
1992 $this->setUser($this->students[2]);
1993 $now = time();
1994 $submission = $assign->get_user_submission($this->students[2]->id, true);
1995 $data = new stdClass();
1996 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1997 'text' => 'Submission text',
1998 'format' => FORMAT_MOODLE);
1999 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2000 $plugin->save($submission, $data);
2001
2002 // And now submit it for marking.
2003 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2004 $assign->testable_update_submission($submission, $this->students[2]->id, true, false);
2005
2006 // Mark the submission as graded.
2007 $this->setUser($this->teachers[0]);
2008 $data = new stdClass();
2009 $data->grade = '0.0';
2010 $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
2011
2012 // Check the student can see the grade.
2013 $this->setUser($this->students[2]);
2014 $output = $assign->view_student_summary($this->students[2], true);
2015 $this->assertNotEquals(false, strpos($output, '0.0'));
2016
2017 // Check that the student does not have a button for Add a new attempt.
2018 $output = $assign->view_student_summary($this->students[2], true);
2019 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
2020 }
2021
2022
f8d107b3
DM
2023 public function test_markingworkflow() {
2024 global $PAGE;
2025
2026 $this->setUser($this->editingteachers[0]);
2027 $assign = $this->create_instance(array('markingworkflow'=>1));
2028 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2029
13e82f1c 2030 // Mark the submission and set to notmarked.
f8d107b3
DM
2031 $this->setUser($this->teachers[0]);
2032 $data = new stdClass();
2033 $data->grade = '50.0';
2034 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
2035 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2036
2037 // Check the student can't see the grade.
2038 $this->setUser($this->students[0]);
2039 $output = $assign->view_student_summary($this->students[0], true);
2040 $this->assertEquals(false, strpos($output, '50.0'));
2041
5047b0ea
TB
2042 // Make sure the grade isn't pushed to the gradebook.
2043 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2044 $this->assertEmpty($grades);
2045
13e82f1c 2046 // Mark the submission and set to inmarking.
f8d107b3
DM
2047 $this->setUser($this->teachers[0]);
2048 $data = new stdClass();
2049 $data->grade = '50.0';
2050 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
2051 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2052
2053 // Check the student can't see the grade.
2054 $this->setUser($this->students[0]);
2055 $output = $assign->view_student_summary($this->students[0], true);
2056 $this->assertEquals(false, strpos($output, '50.0'));
2057
5047b0ea
TB
2058 // Make sure the grade isn't pushed to the gradebook.
2059 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2060 $this->assertEmpty($grades);
2061
13e82f1c 2062 // Mark the submission and set to readyforreview.
f8d107b3
DM
2063 $this->setUser($this->teachers[0]);
2064 $data = new stdClass();
2065 $data->grade = '50.0';
2066 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
2067 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2068
2069 // Check the student can't see the grade.
2070 $this->setUser($this->students[0]);
2071 $output = $assign->view_student_summary($this->students[0], true);
2072 $this->assertEquals(false, strpos($output, '50.0'));
2073
5047b0ea
TB
2074 // Make sure the grade isn't pushed to the gradebook.
2075 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2076 $this->assertEmpty($grades);
2077
13e82f1c 2078 // Mark the submission and set to inreview.
f8d107b3
DM
2079 $this->setUser($this->teachers[0]);
2080 $data = new stdClass();
2081 $data->grade = '50.0';
2082 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
2083 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2084
2085 // Check the student can't see the grade.
2086 $this->setUser($this->students[0]);
2087 $output = $assign->view_student_summary($this->students[0], true);
2088 $this->assertEquals(false, strpos($output, '50.0'));
2089
5047b0ea
TB
2090 // Make sure the grade isn't pushed to the gradebook.
2091 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2092 $this->assertEmpty($grades);
2093
13e82f1c 2094 // Mark the submission and set to readyforrelease.
f8d107b3
DM
2095 $this->setUser($this->teachers[0]);
2096 $data = new stdClass();
2097 $data->grade = '50.0';
2098 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
2099 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2100
2101 // Check the student can't see the grade.
2102 $this->setUser($this->students[0]);
2103 $output = $assign->view_student_summary($this->students[0], true);
2104 $this->assertEquals(false, strpos($output, '50.0'));
2105
5047b0ea
TB
2106 // Make sure the grade isn't pushed to the gradebook.
2107 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2108 $this->assertEmpty($grades);
2109
13e82f1c 2110 // Mark the submission and set to released.
f8d107b3
DM
2111 $this->setUser($this->teachers[0]);
2112 $data = new stdClass();
2113 $data->grade = '50.0';
2114 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
2115 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2116
2117 // Check the student can see the grade.
2118 $this->setUser($this->students[0]);
2119 $output = $assign->view_student_summary($this->students[0], true);
2120 $this->assertNotEquals(false, strpos($output, '50.0'));
5047b0ea
TB
2121
2122 // Make sure the grade is pushed to the gradebook.
2123 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2124 $this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
f8d107b3
DM
2125 }
2126
2127 public function test_markerallocation() {
2128 global $PAGE;
2129
2130 $this->setUser($this->editingteachers[0]);
13e82f1c 2131 $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
f8d107b3
DM
2132 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2133
13e82f1c 2134 // Allocate marker to submission.
f8d107b3
DM
2135 $data = new stdClass();
2136 $data->allocatedmarker = $this->teachers[0]->id;
2137 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2138
13e82f1c 2139 // Check the allocated marker can view the submission.
f8d107b3
DM
2140 $this->setUser($this->teachers[0]);
2141 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
2142 $output = $assign->get_renderer()->render($gradingtable);
2143 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
2144
13e82f1c 2145 // Check that other teachers can't view this submission.
f8d107b3
DM
2146 $this->setUser($this->teachers[1]);
2147 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
2148 $output = $assign->get_renderer()->render($gradingtable);
2149 $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
2150 }
76e77b05 2151
52f3e060
RT
2152 /**
2153 * @expectedException moodle_exception
2154 */
57fbd5f9
DW
2155 public function test_teacher_submit_for_student() {
2156 global $PAGE;
2157
2158 $this->preventResetByRollback();
2159 $sink = $this->redirectMessages();
2160
2161 $this->setUser($this->editingteachers[0]);
2162
2163 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
2164 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2165
2166 $this->setUser($this->students[0]);
2167 // Simulate a submission.
2168 $data = new stdClass();
2169 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2170 'text'=>'Student submission text',
2171 'format'=>FORMAT_MOODLE);
2172
2173 $notices = array();
2174 $assign->save_submission($data, $notices);
2175
2176 // Check that the submission text was saved.
2177 $output = $assign->view_student_summary($this->students[0], true);
2178 $this->assertContains('Student submission text', $output, 'Contains student submission text');
2179
2180 // Check that a teacher teacher with the extra capability can edit a students submission.
2181 $this->setUser($this->teachers[0]);
2182 $data = new stdClass();
2183 $data->userid = $this->students[0]->id;
2184 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2185 'text'=>'Teacher edited submission text',
2186 'format'=>FORMAT_MOODLE);
2187
2188 // Add the required capability.
2189 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
2190 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2191 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
2192 accesslib_clear_all_caches_for_unit_testing();
2193
2194 // Try to save the submission.
2195 $notices = array();
2196 $assign->save_submission($data, $notices);
2197
2198 // Check that the teacher can submit the students work.
2199 $data = new stdClass();
2200 $data->userid = $this->students[0]->id;
2201 $notices = array();
2202 $assign->submit_for_grading($data, $notices);
2203
2204 // Revert to draft so the student can edit it.
2205 $assign->revert_to_draft($this->students[0]->id);
2206
2207 $this->setUser($this->students[0]);
2208
2209 // Check that the submission text was saved.
2210 $output = $assign->view_student_summary($this->students[0], true);
2211 $this->assertContains('Teacher edited submission text', $output, 'Contains student submission text');
2212
2213 // Check that the student can submit their work.
2214 $data = new stdClass();
2215 $assign->submit_for_grading($data, $notices);
2216
2217 $output = $assign->view_student_summary($this->students[0], true);
2218 $this->assertNotContains(get_string('addsubmission', 'assign'), $output);
2219
2220 // Set to a default editing teacher who should not be able to edit this submission.
2221 $this->setUser($this->editingteachers[1]);
2222
2223 // Revert to draft so the submission is editable.
2224 $assign->revert_to_draft($this->students[0]->id);
2225
2226 $data = new stdClass();
2227 $data->userid = $this->students[0]->id;
2228 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2229 'text'=>'Teacher 2 edited submission text',
2230 'format'=>FORMAT_MOODLE);
2231
2232 $notices = array();
57fbd5f9
DW
2233 $assign->save_submission($data, $notices);
2234
2235 $sink->close();
2236 }
2237
9054c04d 2238 public function test_disable_submit_after_cutoff_date() {
2239 global $PAGE;
2240
2241 $this->setUser($this->editingteachers[0]);
2242 $now = time();
2243 $tomorrow = $now + 24*60*60;
2244 $lastweek = $now - 7*24*60*60;
2245 $yesterday = $now - 24*60*60;
2246
2247 $assign = $this->create_instance(array('duedate'=>$yesterday,
2248 'cutoffdate'=>$tomorrow,
2249 'assignsubmission_onlinetext_enabled'=>1));
2250 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2251
2252 // Student should be able to see an add submission button.
2253 $this->setUser($this->students[0]);
2254 $output = $assign->view_student_summary($this->students[0], true);
2255 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
2256
2257 // Add a submission but don't submit now.
2258 $submission = $assign->get_user_submission($this->students[0]->id, true);
2259 $data = new stdClass();
2260 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2261 'text'=>'Submission text',
2262 'format'=>FORMAT_MOODLE);
2263 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2264 $plugin->save($submission, $data);
2265
2266 // Create another instance with cut-off and due-date already passed.
2267 $this->setUser($this->editingteachers[0]);
2268 $now = time();
2269 $assign = $this->create_instance(array('duedate'=>$lastweek,
2270 'cutoffdate'=>$yesterday,
2271 'assignsubmission_onlinetext_enabled'=>1));
2272
2273 $this->setUser($this->students[0]);
2274 $output = $assign->view_student_summary($this->students[0], true);
2275 $this->assertNotContains($output, get_string('editsubmission', 'assign'),
2276 'Should not be able to edit after cutoff date.');
2277 $this->assertNotContains($output, get_string('submitassignment', 'assign'),
2278 'Should not be able to submit after cutoff date.');
2279 }
f159ad73 2280 /**
2281 * Testing for submission comment plugin settings
2282 */
2283 public function test_submission_comment_plugin_settings() {
2284 global $CFG;
2285
2286 $commentconfig = false;
2287 if (!empty($CFG->usecomments)) {
2288 $commentconfig = $CFG->usecomments;
2289 }
2290
2291 $CFG->usecomments = true;
2292 $assign = $this->create_instance();
2293 $plugin = $assign->get_submission_plugin_by_type('comments');
2294 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2295
2296 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
2297 $plugin = $assign->get_submission_plugin_by_type('comments');
2298 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2299
2300 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
2301 $plugin = $assign->get_submission_plugin_by_type('comments');
2302 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2303
2304 $CFG->usecomments = false;
2305 $assign = $this->create_instance();
2306 $plugin = $assign->get_submission_plugin_by_type('comments');
2307 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2308
2309 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
2310 $plugin = $assign->get_submission_plugin_by_type('comments');
2311 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2312
2313 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
2314 $plugin = $assign->get_submission_plugin_by_type('comments');
2315 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2316
2317 $CFG->usecomments = $commentconfig;
2318 }
2319
c7a73689
DW
2320 /**
2321 * Testing for comment inline settings
2322 */
2323 public function test_feedback_comment_commentinline() {
2324 global $CFG;
2325
2326 $sourcetext = "Hello!
2327
2328I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
2329
2330URL outside a tag: https://moodle.org/logo/logo-240x60.gif
2331Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
2332
2333External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/>
2334External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\"/>
2335Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/>
2336Internal link 2:<img alt=\"Moodle\" src=\"@@PLUGINFILE@@logo-240x60.gif\"/>
2337Anchor link 1:<a href=\"@@PLUGINFILE@@logo-240x60.gif\" alt=\"bananas\">Link text</a>
2338Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
2339";
2340
2341 // Note the internal images have been stripped and the html is purified (quotes fixed in this case).
2342 $filteredtext = "Hello!
2343
2344I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
2345
2346URL outside a tag: https://moodle.org/logo/logo-240x60.gif
2347Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
2348
2349External link 1:<img src=\"https://moodle.org/logo/logo-240x60.gif\" alt=\"Moodle\" />
2350External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\" />
2351Internal link 1:
2352Internal link 2:
2353Anchor link 1:Link text
2354Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
2355";
2356
2357 $this->setUser($this->editingteachers[0]);
2358 $params = array('assignsubmission_onlinetext_enabled' => 1,
2359 'assignfeedback_comments_enabled' => 1,
2360 'assignfeedback_comments_commentinline' => 1);
2361 $assign = $this->create_instance($params);
2362
2363 $this->setUser($this->students[0]);
2364 // Add a submission but don't submit now.
2365 $submission = $assign->get_user_submission($this->students[0]->id, true);
2366 $data = new stdClass();
2367
2368 // Test the internal link is stripped, but the external one is not.
2369 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2370 'text'=>$sourcetext,
2371 'format'=>FORMAT_MOODLE);
2372
2373 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2374 $plugin->save($submission, $data);
2375
2376 $this->setUser($this->editingteachers[0]);
2377
2378 $data = new stdClass();
2379 require_once($CFG->dirroot . '/mod/assign/gradeform.php');
2380 $pagination = array('userid'=>$this->students[0]->id,
2381 'rownum'=>0,
2382 'last'=>true,
3fca6937 2383 'useridlistid' => $assign->get_useridlist_key_id(),
c7a73689
DW
2384 'attemptnumber'=>0);
2385 $formparams = array($assign, $data, $pagination);
2386 $mform = new mod_assign_grade_form(null, $formparams);
2387
2388 $this->assertEquals($filteredtext, $data->assignfeedbackcomments_editor['text']);
2389 }
2390
f159ad73 2391 /**
2392 * Testing for feedback comment plugin settings
2393 */
2394 public function test_feedback_plugin_settings() {
2395
2396 $assign = $this->create_instance();
2397 $plugin = $assign->get_feedback_plugin_by_type('comments');
2398 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2399
2400 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 0));
2401 $plugin = $assign->get_feedback_plugin_by_type('comments');
2402 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2403
2404 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
2405 $plugin = $assign->get_feedback_plugin_by_type('comments');
2406 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2407 }
456d7bc7
RT
2408
2409 /**
2410 * Testing if gradebook feedback plugin is enabled.
2411 */
2412 public function test_is_gradebook_feedback_enabled() {
2413 $adminconfig = get_config('assign');
2414 $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
2415
2416 // Create assignment with gradebook feedback enabled and grade = 0.
2417 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 1, 'grades' => 0));
2418
2419 // Get gradebook feedback plugin.
2420 $gradebookplugintype = str_replace('assignfeedback_', '', $gradebookplugin);
2421 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
2422 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2423 $this->assertEquals(1, $assign->is_gradebook_feedback_enabled());
2424
2425 // Create assignment with gradebook feedback disabled and grade = 0.
2426 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 0, 'grades' => 0));
2427 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
2428 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2429 }
57fbd5f9
DW
2430
2431 /**
2432 * Testing can_edit_submission
2433 */
2434 public function test_can_edit_submission() {
2435 global $PAGE, $DB;
2436 $this->create_extra_users();
2437
2438 $this->setAdminUser();
2439 // Create assignment (onlinetext).
2440 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
2441 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2442
2443 // Check student can edit their own submission.
2444 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->students[0]->id));
2445 // Check student cannot edit others submission.
2446 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->students[1]->id));
2447
2448 // Check teacher cannot (by default) edit a students submission.
2449 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
2450
2451 // Add the required capability to edit a student submission.
2452 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
2453 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2454 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
2455 accesslib_clear_all_caches_for_unit_testing();
2456 // Retest - should now have access.
2457 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
2458
2459 // Force create an assignment with SEPARATEGROUPS.
2460 $data = new stdClass();
2461 $data->courseid = $this->course->id;
2462 $data->name = 'Grouping';
2463 $groupingid = groups_create_grouping($data);
2464 groups_assign_grouping($groupingid, $this->groups[0]->id);
2465 groups_assign_grouping($groupingid, $this->groups[1]->id);
2466 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
2467
2468 // Add the capability to the new assignment for extra students 0 and 1.
2469 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2470 role_assign($roleid, $this->extrastudents[0]->id, $assign->get_context()->id);
2471 role_assign($roleid, $this->extrastudents[1]->id, $assign->get_context()->id);
2472 accesslib_clear_all_caches_for_unit_testing();
2473
2474 // Verify the extra student does not have the capability to edit a submission not in their group.
2475 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[1]->id));
2476 // Verify the extra student does have the capability to edit a submission in their group.
2477 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[0]->id));
2478
2479 }
323f221b
MH
2480
2481 /**
2482 * Test if the view blind details capability works
2483 */
2484 public function test_can_view_blind_details() {
eb4c4661
AN
2485 global $DB;
2486 // Note: The shared setUp leads to terrible tests. Please don't use it.
2487 $roles = $DB->get_records('role', null, '', 'shortname, id');
2488 $course = $this->getDataGenerator()->create_course([]);
323f221b
MH
2489
2490 $student = $this->students[0];// Get a student user.
eb4c4661
AN
2491 $this->getDataGenerator()->enrol_user($student->id,
2492 $course->id,
2493 $roles['student']->id);
2494
323f221b
MH
2495 // Create a teacher. Shouldn't be able to view blind marking ID.
2496 $teacher = $this->getDataGenerator()->create_user();
2497
2498 $this->getDataGenerator()->enrol_user($teacher->id,
eb4c4661
AN
2499 $course->id,
2500 $roles['teacher']->id);
323f221b
MH
2501
2502 // Create a manager.. Should be able to view blind marking ID.
2503 $manager = $this->getDataGenerator()->create_user();
e28d6b29 2504 $this->getDataGenerator()->enrol_user($manager->id,
eb4c4661
AN
2505 $course->id,
2506 $roles['manager']->id);
323f221b
MH
2507
2508 // Generate blind marking assignment.
eb4c4661 2509 $assign = $this->create_instance(array('course' => $course->id, 'blindmarking' => 1));
323f221b
MH
2510 $this->assertEquals(true, $assign->is_blind_marking());
2511
2512 // Test student names are hidden to teacher.
e28d6b29
MG
2513 $this->setUser($teacher);
2514 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
2515 $output = $assign->get_renderer()->render($gradingtable);
323f221b
MH
2516 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign'))); // "Participant" is somewhere on the page.
2517 $this->assertEquals(false, strpos($output, fullname($student))); // Students full name doesn't appear.
2518
2519 // Test student names are visible to manager.
e28d6b29
MG
2520 $this->setUser($manager);
2521 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
2522 $output = $assign->get_renderer()->render($gradingtable);
59e95487
MH
2523 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign')));
2524 $this->assertEquals(true, strpos($output, fullname($student)));
323f221b 2525 }
6d6e297b
DM
2526
2527 /**
2528 * Testing get_shared_group_members
2529 */
2530 public function test_get_shared_group_members() {
2531 $this->create_extra_users();
2532 $this->setAdminUser();
2533
2534 // Force create an assignment with SEPARATEGROUPS.
2535 $data = new stdClass();
2536 $data->courseid = $this->course->id;
2537 $data->name = 'Grouping';
2538 $groupingid = groups_create_grouping($data);
2539 groups_assign_grouping($groupingid, $this->groups[0]->id);
2540 groups_assign_grouping($groupingid, $this->groups[1]->id);
2541 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
2542 $cm = $assign->get_course_module();
2543
2544 // Add the capability to access allgroups.
2545 $roleid = create_role('Access all groups role', 'accessallgroupsrole', '');
2546 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $assign->get_context()->id);
2547 role_assign($roleid, $this->extrastudents[3]->id, $assign->get_context()->id);
2548 accesslib_clear_all_caches_for_unit_testing();
2549
2550 // Get shared group members for students 0 and 1.
2551 $groupmembers = array();
2552 $groupmembers[0] = $assign->get_shared_group_members($cm, $this->students[0]->id);
2553 $groupmembers[1] = $assign->get_shared_group_members($cm, $this->students[1]->id);
2554
2555 // They should share groups with extrastudents 0 and 1.
2556 $this->assertTrue(in_array($this->extrastudents[0]->id, $groupmembers[0]));
2557 $this->assertFalse(in_array($this->extrastudents[0]->id, $groupmembers[1]));
2558 $this->assertTrue(in_array($this->extrastudents[1]->id, $groupmembers[1]));
2559 $this->assertFalse(in_array($this->extrastudents[1]->id, $groupmembers[0]));
2560
2561 // Lists of group members for students and extrastudents should be the same.
2562 $this->assertEquals($groupmembers[0], $assign->get_shared_group_members($cm, $this->extrastudents[0]->id));
2563 $this->assertEquals($groupmembers[1], $assign->get_shared_group_members($cm, $this->extrastudents[1]->id));
2564
2565 // Get all group members for extrastudent 3 wich can access all groups.
2566 $allgroupmembers = $assign->get_shared_group_members($cm, $this->extrastudents[3]->id);
2567
2568 // Extrastudent 3 should see students 0 and 1, extrastudent 0 and 1.
2569 $this->assertTrue(in_array($this->students[0]->id, $allgroupmembers));
2570 $this->assertTrue(in_array($this->students[1]->id, $allgroupmembers));
2571 $this->assertTrue(in_array($this->extrastudents[0]->id, $allgroupmembers));
2572 $this->assertTrue(in_array($this->extrastudents[1]->id , $allgroupmembers));
2573 }
47f48152 2574
92ea1fa0
JL
2575 /**
2576 * Test get plugins file areas
2577 */
2578 public function test_get_plugins_file_areas() {
2579 $this->setUser($this->editingteachers[0]);
2580 $assign = $this->create_instance();
2581
2582 // Test that all the submission and feedback plugins are returning the expected file aras.
2583 $usingfilearea = 0;
11ee4f71 2584 $coreplugins = core_plugin_manager::standard_plugins_list('assignsubmission');
92ea1fa0
JL
2585 foreach ($assign->get_submission_plugins() as $plugin) {
2586 $type = $plugin->get_type();
11ee4f71
AO
2587 if (!in_array($type, $coreplugins)) {
2588 continue;
2589 }
92ea1fa0
JL
2590 $fileareas = $plugin->get_file_areas();
2591
2592 if ($type == 'onlinetext') {
2593 $this->assertEquals(array('submissions_onlinetext' => 'Online text'), $fileareas);
2594 $usingfilearea++;
2595 } else if ($type == 'file') {
2596 $this->assertEquals(array('submission_files' => 'File submissions'), $fileareas);
2597 $usingfilearea++;
2598 } else {
2599 $this->assertEmpty($fileareas);
2600 }
2601 }
2602 $this->assertEquals(2, $usingfilearea);
2603
2604 $usingfilearea = 0;
11ee4f71 2605 $coreplugins = core_plugin_manager::standard_plugins_list('assignfeedback');
92ea1fa0
JL
2606 foreach ($assign->get_feedback_plugins() as $plugin) {
2607 $type = $plugin->get_type();
11ee4f71
AO
2608 if (!in_array($type, $coreplugins)) {
2609 continue;
2610 }
92ea1fa0
JL
2611 $fileareas = $plugin->get_file_areas();
2612
2613 if ($type == 'editpdf') {
2614 $this->assertEquals(array('download' => 'Annotate PDF'), $fileareas);
2615 $usingfilearea++;
2616 } else if ($type == 'file') {
2617 $this->assertEquals(array('feedback_files' => 'Feedback files'), $fileareas);
2618 $usingfilearea++;
2619 } else {
2620 $this->assertEmpty($fileareas);
2621 }
2622 }
2623 $this->assertEquals(2, $usingfilearea);
2624 }
2625
002864cc
EM
2626 /**
2627 * Test the quicksave grades processor
2628 */
2629 public function test_process_save_quick_grades() {
2630 $this->editingteachers[0]->ignoresesskey = true;
2631 $this->setUser($this->editingteachers[0]);
2632
2633 $assign = $this->create_instance(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL));
2634
2635 // Initially grade the user.
2636 $grade = $assign->get_user_grade($this->students[0]->id, false);
2637 if (!$grade) {
2638 $grade = new stdClass();
2639 $grade->attemptnumber = '';
2640 $grade->timemodified = '';
2641 }
2642 $data = array(
2643 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2644 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2645 'quickgrade_' . $this->students[0]->id => '60.0'
2646 );
2647 $result = $assign->testable_process_save_quick_grades($data);
2648 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2649 $grade = $assign->get_user_grade($this->students[0]->id, false);
2650 $this->assertEquals('60.0', $grade->grade);
2651
2652 // Attempt to grade with a past attempts grade info.
2653 $assign->testable_process_add_attempt($this->students[0]->id);
2654 $data = array(
2655 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2656 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2657 'quickgrade_' . $this->students[0]->id => '50.0'
2658 );
2659 $result = $assign->testable_process_save_quick_grades($data);
2660 $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
2661 $grade = $assign->get_user_grade($this->students[0]->id, false);
2662 $this->assertFalse($grade);
2663
2664 // Attempt to grade a the attempt.
2665 $submission = $assign->get_user_submission($this->students[0]->id, false);
2666 $data = array(
2667 'grademodified_' . $this->students[0]->id => '',
2668 'gradeattempt_' . $this->students[0]->id => $submission->attemptnumber,
2669 'quickgrade_' . $this->students[0]->id => '40.0'
2670 );
2671 $result = $assign->testable_process_save_quick_grades($data);
2672 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2673 $grade = $assign->get_user_grade($this->students[0]->id, false);
2674 $this->assertEquals('40.0', $grade->grade);
2675
2676 // Catch grade update conflicts.
2677 // Save old data for later.
2678 $pastdata = $data;
2679 // Update the grade the 'good' way.
2680 $data = array(
2681 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2682 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2683 'quickgrade_' . $this->students[0]->id => '30.0'
2684 );
2685 $result = $assign->testable_process_save_quick_grades($data);
2686 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2687 $grade = $assign->get_user_grade($this->students[0]->id, false);
2688 $this->assertEquals('30.0', $grade->grade);
2689
2690 // Now update using 'old' data. Should fail.
2691 $result = $assign->testable_process_save_quick_grades($pastdata);
2692 $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
2693 $grade = $assign->get_user_grade($this->students[0]->id, false);
2694 $this->assertEquals('30.0', $grade->grade);
2695 }
0cf8082a
AG
2696
2697 /**
2698 * Test updating activity completion when submitting an assessment.
2699 */
2700 public function test_update_activity_completion_records_solitary_submission() {
2701 $assign = $this->create_instance(array('grade' => 100,
2702 'completion' => COMPLETION_TRACKING_AUTOMATIC,
2703 'requireallteammemberssubmit' => 0));
2704
2705 $cm = $assign->get_course_module();
2706
2707 $student = $this->students[0];
2708 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
2709
2710 $this->setUser($student);
2711
2712 // Simulate a submission.
2713 $data = new stdClass();
2714 $data->onlinetext_editor = array(
2715 'itemid' => file_get_unused_draft_itemid(),
2716 'text' => 'Student submission text',
2717 'format' => FORMAT_MOODLE
2718 );
2719 $completion = new completion_info($this->course);
2720
2721 $notices = array();
2722 $assign->save_submission($data, $notices);
2723
2724 $submission = $assign->get_user_submission($student->id, true);
2725
2726 // Check that completion is not met yet.
2727 $completiondata = $completion->get_data($cm, false, $student->id);
2728 $this->assertEquals(0, $completiondata->completionstate);
2729 $assign->testable_update_activity_completion_records(0, 0, $submission,
2730 $student->id, COMPLETION_COMPLETE, $completion);
2731 // Completion should now be met.
2732 $completiondata = $completion->get_data($cm, false, $student->id);
2733 $this->assertEquals(1, $completiondata->completionstate);
2734 }
2735
2736 /**
2737 * Test updating activity completion when submitting an assessment.
2738 */
2739 public function test_update_activity_completion_records_team_submission() {
2740 $assign = $this->create_instance(array('grade' => 100,
2741 'completion' => COMPLETION_TRACKING_AUTOMATIC,
2742 'teamsubmission' => 1));
2743
2744 $cm = $assign->get_course_module();
2745
2746 $student1 = $this->students[0];
2747 $student2 = $this->students[1];
2748 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
2749
2750 // Put both users into a group.
2751 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
2752 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student1->id));
2753 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student2->id));
2754
2755 $this->setUser($student1);
2756
2757 // Simulate a submission.
2758 $data = new stdClass();
2759 $data->onlinetext_editor = array(
2760 'itemid' => file_get_unused_draft_itemid(),
2761 'text' => 'Student submission text',
2762 'format' => FORMAT_MOODLE
2763 );
2764 $completion = new completion_info($this->course);
2765
2766 $notices = array();
2767 $assign->save_submission($data, $notices);
2768
2769 $submission = $assign->get_user_submission($student1->id, true);
2770 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2771 $submission->groupid = $group1->id;
2772
2773 // Check that completion is not met yet.
2774 $completiondata = $completion->get_data($cm, false, $student1->id);
2775 $this->assertEquals(0, $completiondata->completionstate);
2776 $completiondata = $completion->get_data($cm, false, $student2->id);
2777 $this->assertEquals(0, $completiondata->completionstate);
2778 $assign->testable_update_activity_completion_records(1, 0, $submission, $student1->id,
2779 COMPLETION_COMPLETE, $completion);
2780 // Completion should now be met.
2781 $completiondata = $completion->get_data($cm, false, $student1->id);
2782 $this->assertEquals(1, $completiondata->completionstate);
2783 $completiondata = $completion->get_data($cm, false, $student2->id);
2784 $this->assertEquals(1, $completiondata->completionstate);
2785 }
002864cc 2786}