MDL-49852 mod_assign: Unit tests for activity completion.
[moodle.git] / mod / assign / tests / locallib_test.php
CommitLineData
47f48152
DW
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Unit tests for (some of) mod/assign/locallib.php.
19 *
20 * @package mod_assign
21 * @category phpunit
22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30require_once($CFG->dirroot . '/mod/assign/locallib.php');
31require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
9c986ee0 32require_once($CFG->dirroot . '/mod/assign/tests/base_test.php');
47f48152
DW
33
34/**
35 * Unit tests for (some of) mod/assign/locallib.php.
36 *
37 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 */
9c986ee0 40class mod_assign_locallib_testcase extends mod_assign_base_testcase {
47f48152
DW
41
42 public function test_return_links() {
c2114099 43 global $PAGE;
47f48152
DW
44 $this->setUser($this->editingteachers[0]);
45 $returnaction = 'RETURNACTION';
c2114099 46 $returnparams = array('param'=>'1');
47f48152 47 $assign = $this->create_instance();
c2114099 48 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
47f48152
DW
49 $assign->register_return_link($returnaction, $returnparams);
50 $this->assertEquals($returnaction, $assign->get_return_action());
51 $this->assertEquals($returnparams, $assign->get_return_params());
52 }
53
54 public function test_get_feedback_plugins() {
55 $this->setUser($this->editingteachers[0]);
56 $assign = $this->create_instance();
bd3b3bba 57 $installedplugins = array_keys(core_component::get_plugin_list('assignfeedback'));
11527706
DW
58
59 foreach ($assign->get_feedback_plugins() as $plugin) {
60 $this->assertContains($plugin->get_type(), $installedplugins, 'Feedback plugin not in list of installed plugins');
61 }
47f48152
DW
62 }
63
64 public function test_get_submission_plugins() {
65 $this->setUser($this->editingteachers[0]);
66 $assign = $this->create_instance();
bd3b3bba 67 $installedplugins = array_keys(core_component::get_plugin_list('assignsubmission'));
11527706
DW
68
69 foreach ($assign->get_submission_plugins() as $plugin) {
70 $this->assertContains($plugin->get_type(), $installedplugins, 'Submission plugin not in list of installed plugins');
71 }
47f48152
DW
72 }
73
74 public function test_is_blind_marking() {
75 $this->setUser($this->editingteachers[0]);
76 $assign = $this->create_instance(array('blindmarking'=>1));
77 $this->assertEquals(true, $assign->is_blind_marking());
78
79 // Test cannot see student names.
80 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
81 $output = $assign->get_renderer()->render($gradingtable);
82 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign')));
83
84 // Test students cannot reveal identities.
85 $nopermission = false;
05a6445a 86 $this->students[0]->ignoresesskey = true;
47f48152
DW
87 $this->setUser($this->students[0]);
88 $this->setExpectedException('required_capability_exception');
05a6445a
DW
89 $assign->reveal_identities();
90 $this->students[0]->ignoresesskey = false;
47f48152
DW
91
92 // Test teachers cannot reveal identities.
93 $nopermission = false;
05a6445a 94 $this->teachers[0]->ignoresesskey = true;
47f48152
DW
95 $this->setUser($this->teachers[0]);
96 $this->setExpectedException('required_capability_exception');
05a6445a
DW
97 $assign->reveal_identities();
98 $this->teachers[0]->ignoresesskey = false;
47f48152
DW
99
100 // Test sesskey is required.
47f48152
DW
101 $this->setUser($this->editingteachers[0]);
102 $this->setExpectedException('moodle_exception');
05a6445a 103 $assign->reveal_identities();
47f48152
DW
104
105 // Test editingteacher can reveal identities if sesskey is ignored.
106 $this->editingteachers[0]->ignoresesskey = true;
107 $this->setUser($this->editingteachers[0]);
05a6445a 108 $assign->reveal_identities();
47f48152 109 $this->assertEquals(false, $assign->is_blind_marking());
05a6445a 110 $this->editingteachers[0]->ignoresesskey = false;
47f48152
DW
111
112 // Test student names are visible.
113 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
114 $output = $assign->get_renderer()->render($gradingtable);
115 $this->assertEquals(false, strpos($output, get_string('hiddenuser', 'assign')));
116
117 // Set this back to default.
118 $this->editingteachers[0]->ignoresesskey = false;
119 }
120
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();
318 $document->loadHTML($output);
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();
362 $document->loadHTML($output);
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
47f48152 690 public function test_list_participants() {
c13ac85d 691 global $CFG, $DB;
692
df211804 693 $this->create_extra_users();
47f48152
DW
694 $this->setUser($this->editingteachers[0]);
695 $assign = $this->create_instance(array('grade'=>100));
696
a5c793c3 697 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
e6cc5347
RT
698
699 // Teacher with user preference set should see suspended users as well.
700 set_user_preference('grade_report_showonlyactiveenrol', false);
701 $assign = $this->create_instance(array('grade'=>100));
702 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT,
703 count($assign->list_participants(null, true)));
704
1ecb8044 705 // Non-editing teacher should not see suspended users, even if user preference is set.
e6cc5347
RT
706 $this->setUser($this->teachers[0]);
707 set_user_preference('grade_report_showonlyactiveenrol', false);
708 $assign = $this->create_instance(array('grade'=>100));
709 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($assign->list_participants(null, true)));
c13ac85d 710
711 // Turn on availability and a group restriction, and check that it doesn't
712 // show users who aren't in the group.
713 $CFG->enableavailability = true;
714 $specialgroup = $this->getDataGenerator()->create_group(
715 array('courseid' => $this->course->id));
716 $assign = $this->create_instance(array('grade' => 100,
717 'availability' => json_encode(\core_availability\tree::get_root_json(
718 array(\availability_group\condition::get_json($specialgroup->id))))));
719 groups_add_member($specialgroup, $this->students[0]);
720 groups_add_member($specialgroup, $this->students[1]);
721 $this->assertEquals(2, count($assign->list_participants(null, true)));
47f48152
DW
722 }
723
1b2f9dc6
RW
724 public function test_get_participant_user_not_exist() {
725 $assign = $this->create_instance(array('grade' => 100));
726 $this->assertNull($assign->get_participant('-1'));
727 }
728
729 public function test_get_participant_not_enrolled() {
730 $assign = $this->create_instance(array('grade' => 100));
731 $user = $this->getDataGenerator()->create_user();
732 $this->assertNull($assign->get_participant($user->id));
733 }
734
735 public function test_get_participant_no_submission() {
736 $assign = $this->create_instance(array('grade' => 100));
737 $student = $this->students[0];
738 $participant = $assign->get_participant($student->id);
739
740 $this->assertEquals($student->id, $participant->id);
741 $this->assertFalse($participant->submitted);
742 $this->assertFalse($participant->requiregrading);
743 }
744
745 public function test_get_participant_with_ungraded_submission() {
746 $assign = $this->create_instance(array('grade' => 100));
747 $student = $this->students[0];
748 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
749
750 $this->setUser($student);
751
752 // Simulate a submission.
753 $data = new stdClass();
754 $data->onlinetext_editor = array(
755 'itemid' => file_get_unused_draft_itemid(),
756 'text' => 'Student submission text',
757 'format' => FORMAT_MOODLE
758 );
759
760 $notices = array();
761 $assign->save_submission($data, $notices);
762
763 $data = new stdClass;
764 $data->userid = $student->id;
765 $assign->submit_for_grading($data, array());
766
767 $participant = $assign->get_participant($student->id);
768
769 $this->assertEquals($student->id, $participant->id);
770 $this->assertTrue($participant->submitted);
771 $this->assertTrue($participant->requiregrading);
772 }
773
774 public function test_get_participant_with_graded_submission() {
775 $assign = $this->create_instance(array('grade' => 100));
776 $student = $this->students[0];
777 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
778
779 $this->setUser($student);
780
781 // Simulate a submission.
782 $data = new stdClass();
783 $data->onlinetext_editor = array(
784 'itemid' => file_get_unused_draft_itemid(),
785 'text' => 'Student submission text',
786 'format' => FORMAT_MOODLE
787 );
788
789 $notices = array();
790 $assign->save_submission($data, $notices);
791
792 $data = new stdClass;
793 $data->userid = $student->id;
794 $assign->submit_for_grading($data, array());
795
796 // This is to make sure the grade happens after the submission because
797 // we have no control over the timemodified values.
798 sleep(1);
799 // Grade the submission.
800 $this->setUser($this->teachers[0]);
801
802 $data = new stdClass();
803 $data->grade = '50.0';
804 $assign->testable_apply_grade_to_user($data, $student->id, 0);
805
806 $participant = $assign->get_participant($student->id);
807
808 $this->assertEquals($student->id, $participant->id);
809 $this->assertTrue($participant->submitted);
810 $this->assertFalse($participant->requiregrading);
811 }
812
47f48152 813 public function test_count_teams() {
df211804 814 $this->create_extra_users();
47f48152 815 $this->setUser($this->editingteachers[0]);
2dda9417
DM
816 $assign1 = $this->create_instance(array('teamsubmission' => 1));
817 $this->assertEquals(self::GROUP_COUNT + 1, $assign1->count_teams());
47f48152 818
2dda9417
DM
819 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
820 $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[0]->id, 'groupingid' => $grouping->id));
821 $this->getDataGenerator()->create_grouping_group(array('groupid' => $this->groups[1]->id, 'groupingid' => $grouping->id));
822
e528997a
AH
823 // No active group and non group submissions allowed => 2 groups + the default one.
824 $params = array(
825 'teamsubmission' => 1,
826 'teamsubmissiongroupingid' => $grouping->id,
827 'preventsubmissionnotingroup' => false
828 );
829 $assign2 = $this->create_instance($params);
2dda9417
DM
830 $this->assertEquals(3, $assign2->count_teams());
831
832 // An active group => Just the selected one.
833 $this->assertEquals(1, $assign2->count_teams($this->groups[0]->id));
e528997a
AH
834
835 // No active group and non group submissions allowed => 2 groups + no default one.
836 $params = array('teamsubmission' => 1, 'teamsubmissiongroupingid' => $grouping->id, 'preventsubmissionnotingroup' => true);
837 $assign3 = $this->create_instance($params);
838 $this->assertEquals(2, $assign3->count_teams());
839
840 $assign4 = $this->create_instance(array('teamsubmission' => 1, 'preventsubmissionnotingroup' => true));
841 $this->assertEquals(self::GROUP_COUNT, $assign4->count_teams());
47f48152
DW
842 }
843
e2d2d8a1 844 public function test_submit_to_default_group() {
2dda9417 845 global $DB, $SESSION;
e2d2d8a1
DW
846
847 $this->preventResetByRollback();
848 $sink = $this->redirectMessages();
849
850 $this->setUser($this->editingteachers[0]);
851 $params = array('teamsubmission' => 1,
852 'assignsubmission_onlinetext_enabled' => 1,
2dda9417
DM
853 'submissiondrafts' => 0,
854 'groupmode' => VISIBLEGROUPS);
e2d2d8a1
DW
855 $assign = $this->create_instance($params);
856
857 $newstudent = $this->getDataGenerator()->create_user();
858 $studentrole = $DB->get_record('role', array('shortname'=>'student'));
859 $this->getDataGenerator()->enrol_user($newstudent->id,
860 $this->course->id,
861 $studentrole->id);
862 $this->setUser($newstudent);
863 $data = new stdClass();
864 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
865 'text'=>'Submission text',
866 'format'=>FORMAT_MOODLE);
867 $notices = array();
868
869 $group = $assign->get_submission_group($newstudent->id);
870 $this->assertFalse($group, 'New student is in default group');
871 $assign->save_submission($data, $notices);
872 $this->assertEmpty($notices, 'No errors on save submission');
873
2dda9417
DM
874 // Set active groups to all groups.
875 $this->setUser($this->teachers[0]);
876 $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
877 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
878
879 // Set an active group.
880 $anothergroup = $this->groups[0];
881 $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
882 $this->assertEquals(0, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
883
e2d2d8a1
DW
884 $sink->close();
885 }
886
47f48152 887 public function test_count_submissions() {
2dda9417
DM
888 global $SESSION;
889
df211804 890 $this->create_extra_users();
47f48152 891 $this->setUser($this->editingteachers[0]);
2dda9417 892 $assign1 = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1));
47f48152
DW
893
894 // Simulate a submission.
a5c793c3 895 $this->setUser($this->extrastudents[0]);
2dda9417 896 $submission = $assign1->get_user_submission($this->extrastudents[0]->id, true);
9e3eee67 897 $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
2dda9417 898 $assign1->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
899 // Leave this one as DRAFT.
900 $data = new stdClass();
901 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
902 'text'=>'Submission text',
903 'format'=>FORMAT_MOODLE);
2dda9417 904 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
905 $plugin->save($submission, $data);
906
907 // Simulate adding a grade.
908 $this->setUser($this->teachers[0]);
909 $data = new stdClass();
910 $data->grade = '50.0';
2dda9417 911 $assign1->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
47f48152
DW
912
913 // Simulate a submission.
a5c793c3 914 $this->setUser($this->extrastudents[1]);
2dda9417 915 $submission = $assign1->get_user_submission($this->extrastudents[1]->id, true);
47f48152 916 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 917 $assign1->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
47f48152
DW
918 $data = new stdClass();
919 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
920 'text'=>'Submission text',
921 'format'=>FORMAT_MOODLE);
2dda9417 922 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
923 $plugin->save($submission, $data);
924
925 // Simulate a submission.
a5c793c3 926 $this->setUser($this->extrastudents[2]);
2dda9417 927 $submission = $assign1->get_user_submission($this->extrastudents[2]->id, true);
47f48152 928 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 929 $assign1->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
47f48152
DW
930 $data = new stdClass();
931 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
932 'text'=>'Submission text',
933 'format'=>FORMAT_MOODLE);
2dda9417 934 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
935 $plugin->save($submission, $data);
936
937 // Simulate a submission.
a5c793c3 938 $this->setUser($this->extrastudents[3]);
2dda9417 939 $submission = $assign1->get_user_submission($this->extrastudents[3]->id, true);
47f48152 940 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 941 $assign1->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
47f48152
DW
942 $data = new stdClass();
943 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
944 'text'=>'Submission text',
945 'format'=>FORMAT_MOODLE);
2dda9417 946 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
47f48152
DW
947 $plugin->save($submission, $data);
948
e6cc5347
RT
949 // Simulate a submission for suspended user, this will never be counted.
950 $this->setUser($this->extrastudents[3]);
2dda9417 951 $submission = $assign1->get_user_submission($this->extrasuspendedstudents[0]->id, true);
e6cc5347 952 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2dda9417 953 $assign1->testable_update_submission($submission, $this->extrasuspendedstudents[0]->id, true, false);
e6cc5347
RT
954 $data = new stdClass();
955 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
956 'text'=>'Submission text',
957 'format'=>FORMAT_MOODLE);
2dda9417 958 $plugin = $assign1->get_submission_plugin_by_type('onlinetext');
e6cc5347
RT
959 $plugin->save($submission, $data);
960
fb6bae3e
DW
961 // Wait 1 second so the submission and grade do not have the same timemodified.
962 sleep(1);
47f48152 963 // Simulate adding a grade.
50c734e8 964 $this->setUser($this->editingteachers[0]);
47f48152
DW
965 $data = new stdClass();
966 $data->grade = '50.0';
2dda9417
DM
967 $assign1->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
968 $assign1->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
47f48152 969
ab14ab74
FM
970 // Create a new submission with status NEW.
971 $this->setUser($this->extrastudents[4]);
2dda9417
DM
972 $submission = $assign1->get_user_submission($this->extrastudents[4]->id, true);
973
974 $this->assertEquals(2, $assign1->count_grades());
975 $this->assertEquals(4, $assign1->count_submissions());
976 $this->assertEquals(5, $assign1->count_submissions(true));
977 $this->assertEquals(2, $assign1->count_submissions_need_grading());
978 $this->assertEquals(3, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
979 $this->assertEquals(1, $assign1->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
980
981 // Groups.
982 $assign2 = $this->create_instance(array(
983 'assignsubmission_onlinetext_enabled' => 1,
984 'groupmode' => VISIBLEGROUPS
985 ));
986
987 $this->setUser($this->extrastudents[1]);
988 $submission = $assign2->get_user_submission($this->extrastudents[1]->id, true);
989 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
990 $assign2->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
991 $data = new stdClass();
992 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
993 'text' => 'Submission text',
994 'format' => FORMAT_MOODLE);
995 $plugin = $assign2->get_submission_plugin_by_type('onlinetext');
996 $plugin->save($submission, $data);
997
998 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
999
1000 // Set active groups to all groups.
1001 $this->setUser($this->teachers[0]);
1002 $SESSION->activegroup[$this->course->id]['aag'][0] = 0;
1003 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1004
1005 // Set the user group.
1006 $studentgroups = groups_get_user_groups($this->course->id, $this->extrastudents[1]->id);
1007 $this->assertEquals(1, count($studentgroups));
1008 $studentgroup = array_pop($studentgroups);
1009 $SESSION->activegroup[$this->course->id]['aag'][0] = $studentgroup[0];
1010 $this->assertEquals(1, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1011
1012 // Set another group.
1013 $anothergroup = $this->groups[0];
1014 $this->assertNotEquals($anothergroup->id, $studentgroup[0]);
1015 $SESSION->activegroup[$this->course->id]['aag'][0] = (int)$anothergroup->id;
1016 $this->assertEquals(0, $assign2->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
47f48152
DW
1017 }
1018
ab14ab74
FM
1019 public function test_count_submissions_for_groups() {
1020 $this->create_extra_users();
1021 $groupid = null;
1022 $this->setUser($this->editingteachers[0]);
1023 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled' => 1, 'teamsubmission' => 1));
1024
1025 // Simulate a submission.
1026 $this->setUser($this->extrastudents[0]);
1027 $submission = $assign->get_group_submission($this->extrastudents[0]->id, $groupid, true);
1028 $submission->status = ASSIGN_SUBMISSION_STATUS_DRAFT;
1029 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
1030 // Leave this one as DRAFT.
1031 $data = new stdClass();
1032 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1033 'text' => 'Submission text',
1034 'format' => FORMAT_MOODLE);
1035 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1036 $plugin->save($submission, $data);
1037
1038 // Simulate adding a grade.
1039 $this->setUser($this->teachers[0]);
1040 $data = new stdClass();
1041 $data->grade = '50.0';
1042 $assign->testable_apply_grade_to_user($data, $this->extrastudents[0]->id, 0);
1043
1044 // Simulate a submission.
1045 $this->setUser($this->extrastudents[1]);
1046 $submission = $assign->get_group_submission($this->extrastudents[1]->id, $groupid, true);
1047 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1048 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, false);
1049 $data = new stdClass();
1050 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1051 'text' => 'Submission text',
1052 'format' => FORMAT_MOODLE);
1053 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1054 $plugin->save($submission, $data);
1055
1056 // Simulate a submission.
1057 $this->setUser($this->extrastudents[2]);
1058 $submission = $assign->get_group_submission($this->extrastudents[2]->id, $groupid, true);
1059 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1060 $assign->testable_update_submission($submission, $this->extrastudents[2]->id, true, false);
1061 $data = new stdClass();
1062 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1063 'text' => 'Submission text',
1064 'format' => FORMAT_MOODLE);
1065 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1066 $plugin->save($submission, $data);
1067
1068 // Simulate a submission.
1069 $this->setUser($this->extrastudents[3]);
1070 $submission = $assign->get_group_submission($this->extrastudents[3]->id, $groupid, true);
1071 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1072 $assign->testable_update_submission($submission, $this->extrastudents[3]->id, true, false);
1073 $data = new stdClass();
1074 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1075 'text' => 'Submission text',
1076 'format' => FORMAT_MOODLE);
1077 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1078 $plugin->save($submission, $data);
1079
1080 // Simulate adding a grade.
50c734e8 1081 $this->setUser($this->editingteachers[0]);
ab14ab74
FM
1082 $data = new stdClass();
1083 $data->grade = '50.0';
1084 $assign->testable_apply_grade_to_user($data, $this->extrastudents[3]->id, 0);
1085 $assign->testable_apply_grade_to_user($data, $this->extrasuspendedstudents[0]->id, 0);
1086
1087 // Create a new submission with status NEW.
1088 $this->setUser($this->extrastudents[4]);
1089 $submission = $assign->get_group_submission($this->extrastudents[4]->id, $groupid, true);
1090
1091 $this->assertEquals(2, $assign->count_grades());
1092 $this->assertEquals(4, $assign->count_submissions());
1093 $this->assertEquals(5, $assign->count_submissions(true));
1094 $this->assertEquals(3, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED));
1095 $this->assertEquals(1, $assign->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_DRAFT));
1096 }
1097
47f48152 1098 public function test_get_grading_userid_list() {
df211804 1099 $this->create_extra_users();
47f48152
DW
1100 $this->setUser($this->editingteachers[0]);
1101 $assign = $this->create_instance();
1102
1103 $users = $assign->testable_get_grading_userid_list();
a5c793c3 1104 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT, count($users));
e6cc5347
RT
1105
1106 $this->setUser($this->editingteachers[0]);
1107 set_user_preference('grade_report_showonlyactiveenrol', false);
1108 $assign = $this->create_instance();
1109
1110 $users = $assign->testable_get_grading_userid_list();
1111 $this->assertEquals(self::DEFAULT_STUDENT_COUNT + self::EXTRA_STUDENT_COUNT + self::EXTRA_SUSPENDED_COUNT, count($users));
47f48152
DW
1112 }
1113
1114 public function test_cron() {
1115 // First run cron so there are no messages waiting to be sent (from other tests).
1116 cron_setup_user();
1117 assign::cron();
1118
1119 // Now create an assignment and add some feedback.
1120 $this->setUser($this->editingteachers[0]);
8e1266bf 1121 $assign = $this->create_instance(array('sendstudentnotifications'=>1));
47f48152
DW
1122
1123 // Simulate adding a grade.
1124 $this->setUser($this->teachers[0]);
1125 $data = new stdClass();
1126 $data->grade = '50.0';
df211804 1127 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
4d2bd673 1128 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
47f48152 1129
f7dc9871
DW
1130 $data->sendstudentnotifications = false;
1131 $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
1132
47f48152
DW
1133 // Now run cron and see that one message was sent.
1134 $this->preventResetByRollback();
1135 $sink = $this->redirectMessages();
1136 cron_setup_user();
4d2bd673 1137 $this->expectOutputRegex('/Done processing 2 assignment submissions/');
47f48152
DW
1138 assign::cron();
1139
1140 $messages = $sink->get_messages();
f7dc9871 1141 // The sent count should be 2, because the 3rd one was marked as do not send notifications.
4d2bd673 1142 $this->assertEquals(2, count($messages));
47f48152
DW
1143 $this->assertEquals(1, $messages[0]->notification);
1144 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
a4b10a52
ZD
1145
1146 // Regrading a grade causes a notification to the user.
1147 $data->sendstudentnotifications = true;
1148 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1149 assign::cron();
1150 $messages = $sink->get_messages();
1151 $this->assertEquals(3, count($messages));
47f48152
DW
1152 }
1153
70cfc878
JF
1154 /**
1155 * Test delivery of grade notifications as controlled by marking workflow.
1156 */
1157 public function test_markingworkflow_cron() {
1158 // First run cron so there are no messages waiting to be sent (from other tests).
1159 cron_setup_user();
1160 assign::cron();
1161
1162 // Now create an assignment with marking workflow enabled.
1163 $this->setUser($this->editingteachers[0]);
1164 $assign = $this->create_instance(array('sendstudentnotifications' => 1, 'markingworkflow' => 1));
1165
1166 // Simulate adding a grade.
1167 $this->setUser($this->teachers[0]);
1168 $data = new stdClass();
1169 $data->grade = '50.0';
1170
1171 // This student will not receive notification.
1172 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
1173 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1174
1175 // This student will receive notification.
1176 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
1177 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
1178
1179 // Now run cron and see that one message was sent.
1180 $this->preventResetByRollback();
1181 $sink = $this->redirectMessages();
1182 cron_setup_user();
1183 $this->expectOutputRegex('/Done processing 1 assignment submissions/');
1184 assign::cron();
1185
1186 $messages = $sink->get_messages();
1187 $this->assertEquals(1, count($messages));
1188 $this->assertEquals($messages[0]->useridto, $this->students[1]->id);
1189 $this->assertEquals($assign->get_instance()->name, $messages[0]->contexturlname);
1190 }
1191
47f48152
DW
1192 public function test_is_graded() {
1193 $this->setUser($this->editingteachers[0]);
1194 $assign = $this->create_instance();
1195
1196 // Simulate adding a grade.
1197 $this->setUser($this->teachers[0]);
1198 $data = new stdClass();
1199 $data->grade = '50.0';
df211804 1200 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
47f48152
DW
1201
1202 $this->assertEquals(true, $assign->testable_is_graded($this->students[0]->id));
1203 $this->assertEquals(false, $assign->testable_is_graded($this->students[1]->id));
1204 }
1205
4a47008c
DW
1206 public function test_can_grade() {
1207 global $DB;
1208
1209 $this->setUser($this->editingteachers[0]);
1210 $assign = $this->create_instance();
1211
1212 $this->setUser($this->students[0]);
1213 $this->assertEquals(false, $assign->can_grade());
1214 $this->setUser($this->editingteachers[0]);
1215 $this->assertEquals(true, $assign->can_grade());
1216 $this->setUser($this->teachers[0]);
1217 $this->assertEquals(true, $assign->can_grade());
1218
1219 // Test the viewgrades capability - without mod/assign:grade.
1220 $this->setUser($this->students[0]);
1221 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1222 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
1223 $this->assertEquals(false, $assign->can_grade());
1224 }
1225
47f48152 1226 public function test_can_view_submission() {
4a47008c
DW
1227 global $DB;
1228
e6cc5347 1229 $this->create_extra_users();
47f48152
DW
1230 $this->setUser($this->editingteachers[0]);
1231 $assign = $this->create_instance();
1232
1233 $this->setUser($this->students[0]);
1234 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1235 $this->assertEquals(false, $assign->can_view_submission($this->students[1]->id));
1236 $this->assertEquals(false, $assign->can_view_submission($this->teachers[0]->id));
1237 $this->setUser($this->teachers[0]);
1238 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1239 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1240 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 1241 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
1242 $this->setUser($this->editingteachers[0]);
1243 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1244 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1245 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
e6cc5347 1246 $this->assertEquals(true, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
4a47008c
DW
1247
1248 // Test the viewgrades capability - without mod/assign:grade.
1249 $this->setUser($this->students[0]);
1250 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
1251 assign_capability('mod/assign:viewgrades', CAP_ALLOW, $studentrole->id, $assign->get_context()->id);
1252 $this->assertEquals(true, $assign->can_view_submission($this->students[0]->id));
1253 $this->assertEquals(true, $assign->can_view_submission($this->students[1]->id));
1254 $this->assertEquals(true, $assign->can_view_submission($this->teachers[0]->id));
1255 $this->assertEquals(false, $assign->can_view_submission($this->extrasuspendedstudents[0]->id));
47f48152
DW
1256 }
1257
1258
1259 public function test_update_submission() {
df211804 1260 $this->create_extra_users();
47f48152
DW
1261 $this->setUser($this->editingteachers[0]);
1262 $assign = $this->create_instance();
1263
a5c793c3 1264 $this->setUser($this->extrastudents[0]);
47f48152 1265 $now = time();
a5c793c3
DW
1266 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
1267 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
1268
1269 $this->setUser($this->teachers[0]);
1270 // Verify the gradebook update.
1271 $gradinginfo = grade_get_grades($this->course->id,
1272 'mod',
1273 'assign',
1274 $assign->get_instance()->id,
a5c793c3 1275 $this->extrastudents[0]->id);
47f48152 1276
a5c793c3
DW
1277 $this->assertEquals($this->extrastudents[0]->id,
1278 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
1279
1280 // Now verify group assignments.
1281 $this->setUser($this->editingteachers[0]);
1282 $assign = $this->create_instance(array('teamsubmission'=>1));
1283
a5c793c3 1284 $this->setUser($this->extrastudents[0]);
47f48152 1285 $now = time();
a5c793c3
DW
1286 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1287 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
47f48152 1288
e6cc5347 1289 // Check that at least 2 active members and 1 suspended member of the submission group had their submission updated.
47f48152
DW
1290
1291 $this->setUser($this->editingteachers[0]);
1292 $gradinginfo = grade_get_grades($this->course->id,
1293 'mod',
1294 'assign',
1295 $assign->get_instance()->id,
a5c793c3 1296 $this->extrastudents[0]->id);
47f48152 1297
a5c793c3
DW
1298 $this->assertEquals($this->extrastudents[0]->id,
1299 $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->usermodified);
47f48152
DW
1300
1301 $gradinginfo = grade_get_grades($this->course->id,
1302 'mod',
1303 'assign',
1304 $assign->get_instance()->id,
a5c793c3 1305 $this->extrastudents[self::GROUP_COUNT]->id);
47f48152 1306
a5c793c3
DW
1307 $this->assertEquals($this->extrastudents[self::GROUP_COUNT]->id,
1308 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT]->id]->usermodified);
47f48152 1309
e6cc5347
RT
1310 $gradinginfo = grade_get_grades($this->course->id,
1311 'mod',
1312 'assign',
1313 $assign->get_instance()->id,
1314 $this->extrasuspendedstudents[0]->id);
1315 $this->assertEquals($this->extrasuspendedstudents[0]->id,
1316 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[0]->id]->usermodified);
1317
1318 // Check the same with non-editing teacher and make sure submission is not updated for suspended user.
1319 $this->setUser($this->editingteachers[0]);
1320 $assign = $this->create_instance(array('teamsubmission'=>1));
1321
1322 $this->setUser($this->extrastudents[1]);
1323 $now = time();
1324 $submission = $assign->get_group_submission($this->extrastudents[1]->id, 0, true);
1325 $assign->testable_update_submission($submission, $this->extrastudents[1]->id, true, true);
1326
1327 $this->setUser($this->teachers[0]);
1328 $gradinginfo = grade_get_grades($this->course->id,
1329 'mod',
1330 'assign',
1331 $assign->get_instance()->id,
1332 $this->extrastudents[1]->id);
1333
1334 $this->assertEquals($this->extrastudents[1]->id,
1335 $gradinginfo->items[0]->grades[$this->extrastudents[1]->id]->usermodified);
1336
1337 $gradinginfo = grade_get_grades($this->course->id,
1338 'mod',
1339 'assign',
1340 $assign->get_instance()->id,
1341 $this->extrastudents[self::GROUP_COUNT+1]->id);
1342
1343 $this->assertEquals($this->extrastudents[self::GROUP_COUNT+1]->id,
1344 $gradinginfo->items[0]->grades[$this->extrastudents[self::GROUP_COUNT+1]->id]->usermodified);
1345
1346 $gradinginfo = grade_get_grades($this->course->id,
1347 'mod',
1348 'assign',
1349 $assign->get_instance()->id,
1350 $this->extrasuspendedstudents[1]->id);
1351 $this->assertEquals($this->extrasuspendedstudents[1]->id,
1352 $gradinginfo->items[0]->grades[$this->extrasuspendedstudents[1]->id]->usermodified);
1353
47f48152
DW
1354 // Now verify blind marking.
1355 $this->setUser($this->editingteachers[0]);
1356 $assign = $this->create_instance(array('blindmarking'=>1));
1357
a5c793c3 1358 $this->setUser($this->extrastudents[0]);
47f48152 1359 $now = time();
a5c793c3
DW
1360 $submission = $assign->get_user_submission($this->extrastudents[0]->id, true);
1361 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, false);
47f48152
DW
1362
1363 $this->setUser($this->editingteachers[0]);
1364 $gradinginfo = grade_get_grades($this->course->id,
1365 'mod',
1366 'assign',
1367 $assign->get_instance()->id,
a5c793c3 1368 $this->extrastudents[0]->id);
47f48152 1369
a5c793c3 1370 $this->assertEquals(null, $gradinginfo->items[0]->grades[$this->extrastudents[0]->id]->datesubmitted);
47f48152
DW
1371 }
1372
79397b56 1373 public function test_group_submissions_submit_for_marking_requireallteammemberssubmit() {
2bd27878
DW
1374 global $PAGE;
1375
1376 $this->create_extra_users();
1377 // Now verify group assignments.
1378 $this->setUser($this->editingteachers[0]);
1379 $assign = $this->create_instance(array('teamsubmission'=>1,
1380 'assignsubmission_onlinetext_enabled'=>1,
1381 'submissiondrafts'=>1,
1382 'requireallteammemberssubmit'=>1));
1383 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1384
2bd27878 1385 // Add a submission.
79397b56 1386 $this->setUser($this->extrastudents[0]);
2bd27878
DW
1387 $data = new stdClass();
1388 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1389 'text'=>'Submission text',
1390 'format'=>FORMAT_MOODLE);
1391
1392 $notices = array();
1393 $assign->save_submission($data, $notices);
1394
1395 // Check we can see the submit button.
1396 $output = $assign->view_student_summary($this->extrastudents[0], true);
1397 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1398
1399 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1400 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1401 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1402
1403 // Check that the student does not see "Submit" button.
1404 $output = $assign->view_student_summary($this->extrastudents[0], true);
1405 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1406
1407 // Change to another user in the same group.
1408 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1409 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1410 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1411
1412 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1413 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1414 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1415 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1416 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1417 }
1418
79397b56
DB
1419 public function test_group_submissions_submit_for_marking() {
1420 global $PAGE;
1421
1422 $this->create_extra_users();
1423 // Now verify group assignments.
1424 $this->setUser($this->editingteachers[0]);
a0f8db77 1425 $time = time();
79397b56
DB
1426 $assign = $this->create_instance(array('teamsubmission'=>1,
1427 'assignsubmission_onlinetext_enabled'=>1,
1428 'submissiondrafts'=>1,
1429 'requireallteammemberssubmit'=>0,
a0f8db77 1430 'duedate' => $time - 2*24*60*60));
79397b56
DB
1431 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1432
1433 $this->setUser($this->extrastudents[0]);
1434 // Add a submission.
1435 $data = new stdClass();
1436 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1437 'text'=>'Submission text',
1438 'format'=>FORMAT_MOODLE);
1439
1440 $notices = array();
1441 $assign->save_submission($data, $notices);
1442
1443 // Check we can see the submit button.
1444 $output = $assign->view_student_summary($this->extrastudents[0], true);
1445 $this->assertContains(get_string('submitassignment', 'assign'), $output);
1446 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1447 $difftime = time() - $time;
1448 $this->assertContains(get_string('overdue', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1449
1450 $submission = $assign->get_group_submission($this->extrastudents[0]->id, 0, true);
1451 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1452 $assign->testable_update_submission($submission, $this->extrastudents[0]->id, true, true);
1453
1454 // Check that the student does not see "Submit" button.
1455 $output = $assign->view_student_summary($this->extrastudents[0], true);
1456 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1457
1458 // Change to another user in the same group.
1459 $this->setUser($this->extrastudents[self::GROUP_COUNT]);
1460 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1461 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1462
1463 // Check that time remaining is not overdue.
1464 $this->assertContains(get_string('timeremaining', 'assign'), $output);
a0f8db77
DW
1465 $difftime = time() - $time;
1466 $this->assertContains(get_string('submittedlate', 'assign', format_time(2*24*60*60 + $difftime)), $output);
79397b56
DB
1467
1468 $submission = $assign->get_group_submission($this->extrastudents[self::GROUP_COUNT]->id, 0, true);
1469 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1470 $assign->testable_update_submission($submission, $this->extrastudents[self::GROUP_COUNT]->id, true, true);
1471 $output = $assign->view_student_summary($this->extrastudents[self::GROUP_COUNT], true);
1472 $this->assertNotContains(get_string('submitassignment', 'assign'), $output);
1473 }
1474
47f48152
DW
1475 public function test_submissions_open() {
1476 $this->setUser($this->editingteachers[0]);
1477
1478 $now = time();
1479 $tomorrow = $now + 24*60*60;
1480 $oneweek = $now + 7*24*60*60;
1481 $yesterday = $now - 24*60*60;
1482
1483 $assign = $this->create_instance();
1484 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1485
1486 $assign = $this->create_instance(array('duedate'=>$tomorrow));
1487 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1488
1489 $assign = $this->create_instance(array('duedate'=>$yesterday));
1490 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1491
1492 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$tomorrow));
1493 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1494
1495 $assign = $this->create_instance(array('duedate'=>$yesterday, 'cutoffdate'=>$yesterday));
1496 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1497
1498 $assign->testable_save_user_extension($this->students[0]->id, $tomorrow);
1499 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1500
1501 $assign = $this->create_instance(array('submissiondrafts'=>1));
1502 $this->assertEquals(true, $assign->testable_submissions_open($this->students[0]->id));
1503
1504 $this->setUser($this->students[0]);
1505 $now = time();
1506 $submission = $assign->get_user_submission($this->students[0]->id, true);
1507 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1508 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1509 $this->setUser($this->editingteachers[0]);
1510 $this->assertEquals(false, $assign->testable_submissions_open($this->students[0]->id));
1511 }
1512
1513 public function test_get_graders() {
df211804 1514 $this->create_extra_users();
47f48152 1515 $this->setUser($this->editingteachers[0]);
47f48152 1516
f268fb5d
DW
1517 // Create an assignment with no groups.
1518 $assign = $this->create_instance();
a5c793c3
DW
1519 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1520 self::DEFAULT_EDITING_TEACHER_COUNT +
1521 self::EXTRA_TEACHER_COUNT +
1522 self::EXTRA_EDITING_TEACHER_COUNT,
1523 $assign->testable_get_graders($this->students[0]->id));
47f48152 1524
47f48152 1525 // Force create an assignment with SEPARATEGROUPS.
f268fb5d
DW
1526 $data = new stdClass();
1527 $data->courseid = $this->course->id;
1528 $data->name = 'Grouping';
1529 $groupingid = groups_create_grouping($data);
1530 groups_assign_grouping($groupingid, $this->groups[0]->id);
1531 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
47f48152
DW
1532
1533 $this->setUser($this->students[1]);
a5c793c3 1534 $this->assertCount(4, $assign->testable_get_graders($this->students[0]->id));
f268fb5d
DW
1535 // Note the second student is in a group that is not in the grouping.
1536 // This means that we get all graders that are not in a group in the grouping.
1537 $this->assertCount(10, $assign->testable_get_graders($this->students[1]->id));
47f48152
DW
1538 }
1539
83360c8d
S
1540 public function test_get_notified_users() {
1541 global $CFG, $DB;
1542
1543 $capability = 'mod/assign:receivegradernotifications';
1544 $coursecontext = context_course::instance($this->course->id);
1545 $role = $DB->get_record('role', array('shortname' => 'teacher'));
1546
1547 $this->create_extra_users();
1548 $this->setUser($this->editingteachers[0]);
1549
1550 // Create an assignment with no groups.
1551 $assign = $this->create_instance();
1552
1553 $this->assertCount(self::DEFAULT_TEACHER_COUNT +
1554 self::DEFAULT_EDITING_TEACHER_COUNT +
1555 self::EXTRA_TEACHER_COUNT +
1556 self::EXTRA_EDITING_TEACHER_COUNT,
1557 $assign->testable_get_notifiable_users($this->students[0]->id));
1558
1559 // Change nonediting teachers role to not receive grader notifications.
1560 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1561
1562 $this->assertCount(self::DEFAULT_EDITING_TEACHER_COUNT +
1563 self::EXTRA_EDITING_TEACHER_COUNT,
1564 $assign->testable_get_notifiable_users($this->students[0]->id));
1565
1566 // Reset nonediting teachers role to default.
1567 unassign_capability($capability, $role->id, $coursecontext);
1568
1569 // Force create an assignment with SEPARATEGROUPS.
1570 $data = new stdClass();
1571 $data->courseid = $this->course->id;
1572 $data->name = 'Grouping';
1573 $groupingid = groups_create_grouping($data);
1574 groups_assign_grouping($groupingid, $this->groups[0]->id);
1575 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
1576
1577 $this->setUser($this->students[1]);
1578 $this->assertCount(4, $assign->testable_get_notifiable_users($this->students[0]->id));
1579 // Note the second student is in a group that is not in the grouping.
1580 // This means that we get all graders that are not in a group in the grouping.
1581 $this->assertCount(10, $assign->testable_get_notifiable_users($this->students[1]->id));
1582
1583 // Change nonediting teachers role to not receive grader notifications.
1584 assign_capability($capability, CAP_PROHIBIT, $role->id, $coursecontext);
1585
1586 $this->assertCount(2, $assign->testable_get_notifiable_users($this->students[0]->id));
1587 // Note the second student is in a group that is not in the grouping.
1588 // This means that we get all graders that are not in a group in the grouping.
1589 $this->assertCount(5, $assign->testable_get_notifiable_users($this->students[1]->id));
1590 }
1591
20b7dcfc
DW
1592 public function test_group_members_only() {
1593 global $CFG;
1594
1595 $this->setAdminUser();
1596 $this->create_extra_users();
c13ac85d 1597 $CFG->enableavailability = true;
20b7dcfc
DW
1598 $grouping = $this->getDataGenerator()->create_grouping(array('courseid' => $this->course->id));
1599 groups_assign_grouping($grouping->id, $this->groups[0]->id);
1600
1601 // Force create an assignment with SEPARATEGROUPS.
1602 $instance = $this->getDataGenerator()->create_module('assign', array('course'=>$this->course->id),
c13ac85d 1603 array('availability' => json_encode(\core_availability\tree::get_root_json(array(
1604 \availability_grouping\condition::get_json()))),
1605 'groupingid' => $grouping->id));
20b7dcfc
DW
1606
1607 $cm = get_coursemodule_from_instance('assign', $instance->id);
1608 $context = context_module::instance($cm->id);
1609 $assign = new testable_assign($context, $cm, $this->course);
1610
1611 $this->setUser($this->teachers[0]);
8270f0d0 1612 get_fast_modinfo($this->course, 0, true);
20b7dcfc
DW
1613 $this->assertCount(5, $assign->list_participants(0, true));
1614
1615 }
1616
47f48152
DW
1617 public function test_get_uniqueid_for_user() {
1618 $this->setUser($this->editingteachers[0]);
1619 $assign = $this->create_instance();
1620
1621 foreach ($this->students as $student) {
1622 $uniqueid = $assign->get_uniqueid_for_user($student->id);
1623 $this->assertEquals($student->id, $assign->get_user_id_for_uniqueid($uniqueid));
1624 }
1625 }
1626
46692c3a 1627 public function test_show_student_summary() {
c2114099 1628 global $CFG, $PAGE;
46692c3a
DW
1629
1630 $this->setUser($this->editingteachers[0]);
1631 $assign = $this->create_instance();
c2114099 1632 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
46692c3a
DW
1633
1634 // No feedback should be available because this student has not been graded.
1635 $this->setUser($this->students[0]);
1636 $output = $assign->view_student_summary($this->students[0], true);
1637 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
1638 // Simulate adding a grade.
1639 $this->setUser($this->teachers[0]);
1640 $data = new stdClass();
1641 $data->grade = '50.0';
df211804 1642 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
46692c3a 1643
b0da618b 1644 // Now we should see the feedback.
46692c3a
DW
1645 $this->setUser($this->students[0]);
1646 $output = $assign->view_student_summary($this->students[0], true);
1647 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
1648
1649 // Now hide the grade in gradebook.
1650 $this->setUser($this->teachers[0]);
1651 require_once($CFG->libdir.'/gradelib.php');
1652 $gradeitem = new grade_item(array(
1653 'itemtype' => 'mod',
1654 'itemmodule' => 'assign',
1655 'iteminstance' => $assign->get_instance()->id,
1656 'courseid' => $this->course->id));
1657
1658 $gradeitem->set_hidden(1, false);
1659
1660 // No feedback should be available because the grade is hidden.
1661 $this->setUser($this->students[0]);
1662 $output = $assign->view_student_summary($this->students[0], true);
1663 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
1664
b0da618b 1665 // Do the same but add feedback.
46692c3a
DW
1666 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
1667
1668 $this->setUser($this->teachers[0]);
1669 $grade = $assign->get_user_grade($this->students[0]->id, true);
1670 $data = new stdClass();
1671 $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
1672 'format'=>FORMAT_MOODLE);
1673 $plugin = $assign->get_feedback_plugin_by_type('comments');
1674 $plugin->save($grade, $data);
1675
b0da618b 1676 // Should have feedback but no grade.
46692c3a
DW
1677 $this->setUser($this->students[0]);
1678 $output = $assign->view_student_summary($this->students[0], true);
ea698284 1679 $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback even if there is no grade');
46692c3a
DW
1680 $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
1681 $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
45aac51a 1682
ea698284
AD
1683 // Now hide the grade in gradebook.
1684 $this->setUser($this->teachers[0]);
1685 $gradeitem = new grade_item(array(
1686 'itemtype' => 'mod',
1687 'itemmodule' => 'assign',
1688 'iteminstance' => $assign->get_instance()->id,
1689 'courseid' => $this->course->id));
1690
1691 $gradeitem->set_hidden(1, false);
1692
1693 // No feedback should be available because the grade is hidden.
1694 $this->setUser($this->students[0]);
1695 $output = $assign->view_student_summary($this->students[0], true);
1696 $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
46692c3a
DW
1697 }
1698
df211804
DW
1699 public function test_attempt_reopen_method_manual() {
1700 global $PAGE;
1701
1702 $this->setUser($this->editingteachers[0]);
1703 $assign = $this->create_instance(array('attemptreopenmethod'=>ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
1704 'maxattempts'=>3,
1705 'submissiondrafts'=>1,
1706 'assignsubmission_onlinetext_enabled'=>1));
1707 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1708
1709 // Student should be able to see an add submission button.
1710 $this->setUser($this->students[0]);
1711 $output = $assign->view_student_summary($this->students[0], true);
1712 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1713
1714 // Add a submission.
1715 $now = time();
1716 $submission = $assign->get_user_submission($this->students[0]->id, true);
1717 $data = new stdClass();
1718 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
1719 'text'=>'Submission text',
1720 'format'=>FORMAT_MOODLE);
1721 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1722 $plugin->save($submission, $data);
1723
1724 // And now submit it for marking.
1725 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1726 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1727
1728 // Verify the student cannot make changes to the submission.
1729 $output = $assign->view_student_summary($this->students[0], true);
1730 $this->assertEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1731
1732 // Mark the submission.
1733 $this->setUser($this->teachers[0]);
1734 $data = new stdClass();
1735 $data->grade = '50.0';
1736 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1737
1738 // Check the student can see the grade.
1739 $this->setUser($this->students[0]);
1740 $output = $assign->view_student_summary($this->students[0], true);
1741 $this->assertNotEquals(false, strpos($output, '50.0'));
1742
1743 // Allow the student another attempt.
1744 $this->teachers[0]->ignoresesskey = true;
1745 $this->setUser($this->teachers[0]);
1746 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1747 $this->assertEquals(true, $result);
1748
1749 // Check that the previous attempt is now in the submission history table.
1750 $this->setUser($this->students[0]);
1751 $output = $assign->view_student_summary($this->students[0], true);
1752 // Need a better check.
1753 $this->assertNotEquals(false, strpos($output, 'Submission text'), 'Contains: Submission text');
1754
1755 // Check that the student now has a button for Add a new attempt".
1756 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1757 // Check that the student now does not have a button for Submit.
1758 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
1759
1760 // Check that the student now has a submission history.
1761 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
1762
1763 $this->setUser($this->teachers[0]);
1764 // Check that the grading table loads correctly and contains this user.
1765 // This is also testing that we do not get duplicate rows in the grading table.
1766 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
1767 $output = $assign->get_renderer()->render($gradingtable);
1768 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
1769
1770 // Should be 1 not 2.
1771 $this->assertEquals(1, $assign->count_submissions());
1772 $this->assertEquals(1, $assign->count_submissions_with_status('reopened'));
1773 $this->assertEquals(0, $assign->count_submissions_need_grading());
1774 $this->assertEquals(1, $assign->count_grades());
1775
1776 // Change max attempts to unlimited.
1777 $formdata = clone($assign->get_instance());
1778 $formdata->maxattempts = ASSIGN_UNLIMITED_ATTEMPTS;
1779 $formdata->instance = $formdata->id;
1780 $assign->update_instance($formdata);
1781
9e3eee67
DW
1782 // Mark the submission again.
1783 $data = new stdClass();
1784 $data->grade = '60.0';
1785 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1786
1787 // Check the grade exists.
1788 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
1789 $this->assertEquals(60, (int)$grades[$this->students[0]->id]->rawgrade);
1790
1791 // Check we can reopen still.
df211804
DW
1792 $result = $assign->testable_process_add_attempt($this->students[0]->id);
1793 $this->assertEquals(true, $result);
1794
9e3eee67 1795 // Should no longer have a grade because there is no grade for the latest attempt.
df211804 1796 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
9e3eee67 1797 $this->assertEmpty($grades);
df211804 1798
df211804 1799 }
46692c3a 1800
e77bacab
MP
1801 /**
1802 * Test reopen behavior when in "Reopen until pass" mode.
1803 */
1804 public function test_attempt_reopen_method_untilpass() {
1805 global $PAGE;
1806
1807 $this->setUser($this->editingteachers[0]);
1808 $assign = $this->create_instance(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_UNTILPASS,
1809 'maxattempts' => 3,
1810 'submissiondrafts' => 1,
1811 'assignsubmission_onlinetext_enabled' => 1));
1812 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1813
1814 // Set grade to pass to 80.
1815 $gradeitem = $assign->get_grade_item();
1816 $gradeitem->gradepass = '80.0';
1817 $gradeitem->update();
1818
1819 // Student should be able to see an add submission button.
1820 $this->setUser($this->students[0]);
1821 $output = $assign->view_student_summary($this->students[0], true);
1822 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
1823
1824 // Add a submission.
1825 $now = time();
1826 $submission = $assign->get_user_submission($this->students[0]->id, true);
1827 $data = new stdClass();
1828 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1829 'text' => 'Submission text',
1830 'format' => FORMAT_MOODLE);
1831 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1832 $plugin->save($submission, $data);
1833
1834 // And now submit it for marking.
1835 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1836 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1837
1838 // Verify the student cannot make a new attempt.
1839 $output = $assign->view_student_summary($this->students[0], true);
1840 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1841
1842 // Mark the submission as non-passing.
1843 $this->setUser($this->teachers[0]);
1844 $data = new stdClass();
1845 $data->grade = '50.0';
1846 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1847
1848 // Check the student can see the grade.
1849 $this->setUser($this->students[0]);
1850 $output = $assign->view_student_summary($this->students[0], true);
1851 $this->assertNotEquals(false, strpos($output, '50.0'));
1852
1853 // Check that the student now has a button for Add a new attempt.
1854 $output = $assign->view_student_summary($this->students[0], true);
1855 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1856
1857 // Check that the student now does not have a button for Submit.
1858 $this->assertEquals(false, strpos($output, get_string('submitassignment', 'assign')));
1859
1860 // Check that the student now has a submission history.
1861 $this->assertNotEquals(false, strpos($output, get_string('attempthistory', 'assign')));
1862
1863 // Add a second submission.
1864 $now = time();
1865 $submission = $assign->get_user_submission($this->students[0]->id, true, 1);
1866 $data = new stdClass();
1867 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1868 'text' => 'Submission text',
1869 'format' => FORMAT_MOODLE);
1870 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1871 $plugin->save($submission, $data);
1872
1873 // And now submit it for marking.
1874 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1875 $assign->testable_update_submission($submission, $this->students[0]->id, true, false);
1876
1877 // Mark the submission as passing.
1878 $this->setUser($this->teachers[0]);
1879 $data = new stdClass();
1880 $data->grade = '80.0';
1881 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1882
1883 // Check that the student does not have a button for Add a new attempt.
1884 $this->setUser($this->students[0]);
1885 $output = $assign->view_student_summary($this->students[0], true);
1886 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1887
1888 // Re-mark the submission as not passing.
1889 $this->setUser($this->teachers[0]);
1890 $data = new stdClass();
1891 $data->grade = '50.0';
1892 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 1);
1893
1894 // Check that the student now has a button for Add a new attempt.
1895 $this->setUser($this->students[0]);
1896 $output = $assign->view_student_summary($this->students[0], true);
1897 $this->assertNotEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1898
1899 // Add a submission as a second student.
1900 $this->setUser($this->students[1]);
1901 $now = time();
1902 $submission = $assign->get_user_submission($this->students[1]->id, true);
1903 $data = new stdClass();
1904 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1905 'text' => 'Submission text',
1906 'format' => FORMAT_MOODLE);
1907 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1908 $plugin->save($submission, $data);
1909
1910 // And now submit it for marking.
1911 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1912 $assign->testable_update_submission($submission, $this->students[1]->id, true, false);
1913
1914 // Mark the submission as passing.
1915 $this->setUser($this->teachers[0]);
1916 $data = new stdClass();
1917 $data->grade = '100.0';
1918 $assign->testable_apply_grade_to_user($data, $this->students[1]->id, 0);
1919
1920 // Check the student can see the grade.
1921 $this->setUser($this->students[1]);
1922 $output = $assign->view_student_summary($this->students[1], true);
1923 $this->assertNotEquals(false, strpos($output, '100.0'));
1924
1925 // Check that the student does not have a button for Add a new attempt.
1926 $output = $assign->view_student_summary($this->students[1], true);
1927 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1928
1929 // Set grade to pass to 0, so that no attempts should reopen.
1930 $gradeitem = $assign->get_grade_item();
1931 $gradeitem->gradepass = '0';
1932 $gradeitem->update();
1933
1934 // Add another submission.
1935 $this->setUser($this->students[2]);
1936 $now = time();
1937 $submission = $assign->get_user_submission($this->students[2]->id, true);
1938 $data = new stdClass();
1939 $data->onlinetext_editor = array('itemid' => file_get_unused_draft_itemid(),
1940 'text' => 'Submission text',
1941 'format' => FORMAT_MOODLE);
1942 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
1943 $plugin->save($submission, $data);
1944
1945 // And now submit it for marking.
1946 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
1947 $assign->testable_update_submission($submission, $this->students[2]->id, true, false);
1948
1949 // Mark the submission as graded.
1950 $this->setUser($this->teachers[0]);
1951 $data = new stdClass();
1952 $data->grade = '0.0';
1953 $assign->testable_apply_grade_to_user($data, $this->students[2]->id, 0);
1954
1955 // Check the student can see the grade.
1956 $this->setUser($this->students[2]);
1957 $output = $assign->view_student_summary($this->students[2], true);
1958 $this->assertNotEquals(false, strpos($output, '0.0'));
1959
1960 // Check that the student does not have a button for Add a new attempt.
1961 $output = $assign->view_student_summary($this->students[2], true);
1962 $this->assertEquals(false, strpos($output, get_string('addnewattempt', 'assign')));
1963 }
1964
1965
f8d107b3
DM
1966 public function test_markingworkflow() {
1967 global $PAGE;
1968
1969 $this->setUser($this->editingteachers[0]);
1970 $assign = $this->create_instance(array('markingworkflow'=>1));
1971 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
1972
13e82f1c 1973 // Mark the submission and set to notmarked.
f8d107b3
DM
1974 $this->setUser($this->teachers[0]);
1975 $data = new stdClass();
1976 $data->grade = '50.0';
1977 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED;
1978 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1979
1980 // Check the student can't see the grade.
1981 $this->setUser($this->students[0]);
1982 $output = $assign->view_student_summary($this->students[0], true);
1983 $this->assertEquals(false, strpos($output, '50.0'));
1984
5047b0ea
TB
1985 // Make sure the grade isn't pushed to the gradebook.
1986 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
1987 $this->assertEmpty($grades);
1988
13e82f1c 1989 // Mark the submission and set to inmarking.
f8d107b3
DM
1990 $this->setUser($this->teachers[0]);
1991 $data = new stdClass();
1992 $data->grade = '50.0';
1993 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INMARKING;
1994 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
1995
1996 // Check the student can't see the grade.
1997 $this->setUser($this->students[0]);
1998 $output = $assign->view_student_summary($this->students[0], true);
1999 $this->assertEquals(false, strpos($output, '50.0'));
2000
5047b0ea
TB
2001 // Make sure the grade isn't pushed to the gradebook.
2002 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2003 $this->assertEmpty($grades);
2004
13e82f1c 2005 // Mark the submission and set to readyforreview.
f8d107b3
DM
2006 $this->setUser($this->teachers[0]);
2007 $data = new stdClass();
2008 $data->grade = '50.0';
2009 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW;
2010 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2011
2012 // Check the student can't see the grade.
2013 $this->setUser($this->students[0]);
2014 $output = $assign->view_student_summary($this->students[0], true);
2015 $this->assertEquals(false, strpos($output, '50.0'));
2016
5047b0ea
TB
2017 // Make sure the grade isn't pushed to the gradebook.
2018 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2019 $this->assertEmpty($grades);
2020
13e82f1c 2021 // Mark the submission and set to inreview.
f8d107b3
DM
2022 $this->setUser($this->teachers[0]);
2023 $data = new stdClass();
2024 $data->grade = '50.0';
2025 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW;
2026 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2027
2028 // Check the student can't see the grade.
2029 $this->setUser($this->students[0]);
2030 $output = $assign->view_student_summary($this->students[0], true);
2031 $this->assertEquals(false, strpos($output, '50.0'));
2032
5047b0ea
TB
2033 // Make sure the grade isn't pushed to the gradebook.
2034 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2035 $this->assertEmpty($grades);
2036
13e82f1c 2037 // Mark the submission and set to readyforrelease.
f8d107b3
DM
2038 $this->setUser($this->teachers[0]);
2039 $data = new stdClass();
2040 $data->grade = '50.0';
2041 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE;
2042 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2043
2044 // Check the student can't see the grade.
2045 $this->setUser($this->students[0]);
2046 $output = $assign->view_student_summary($this->students[0], true);
2047 $this->assertEquals(false, strpos($output, '50.0'));
2048
5047b0ea
TB
2049 // Make sure the grade isn't pushed to the gradebook.
2050 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2051 $this->assertEmpty($grades);
2052
13e82f1c 2053 // Mark the submission and set to released.
f8d107b3
DM
2054 $this->setUser($this->teachers[0]);
2055 $data = new stdClass();
2056 $data->grade = '50.0';
2057 $data->workflowstate = ASSIGN_MARKING_WORKFLOW_STATE_RELEASED;
2058 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2059
2060 // Check the student can see the grade.
2061 $this->setUser($this->students[0]);
2062 $output = $assign->view_student_summary($this->students[0], true);
2063 $this->assertNotEquals(false, strpos($output, '50.0'));
5047b0ea
TB
2064
2065 // Make sure the grade is pushed to the gradebook.
2066 $grades = $assign->get_user_grades_for_gradebook($this->students[0]->id);
2067 $this->assertEquals(50, (int)$grades[$this->students[0]->id]->rawgrade);
f8d107b3
DM
2068 }
2069
2070 public function test_markerallocation() {
2071 global $PAGE;
2072
2073 $this->setUser($this->editingteachers[0]);
13e82f1c 2074 $assign = $this->create_instance(array('markingworkflow'=>1, 'markingallocation'=>1));
f8d107b3
DM
2075 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2076
13e82f1c 2077 // Allocate marker to submission.
f8d107b3
DM
2078 $data = new stdClass();
2079 $data->allocatedmarker = $this->teachers[0]->id;
2080 $assign->testable_apply_grade_to_user($data, $this->students[0]->id, 0);
2081
13e82f1c 2082 // Check the allocated marker can view the submission.
f8d107b3
DM
2083 $this->setUser($this->teachers[0]);
2084 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
2085 $output = $assign->get_renderer()->render($gradingtable);
2086 $this->assertEquals(true, strpos($output, $this->students[0]->lastname));
2087
13e82f1c 2088 // Check that other teachers can't view this submission.
f8d107b3
DM
2089 $this->setUser($this->teachers[1]);
2090 $gradingtable = new assign_grading_table($assign, 100, '', 0, true);
2091 $output = $assign->get_renderer()->render($gradingtable);
2092 $this->assertNotEquals(true, strpos($output, $this->students[0]->lastname));
2093 }
76e77b05 2094
3d1331be 2095
159b7f40 2096
57fbd5f9
DW
2097 public function test_teacher_submit_for_student() {
2098 global $PAGE;
2099
2100 $this->preventResetByRollback();
2101 $sink = $this->redirectMessages();
2102
2103 $this->setUser($this->editingteachers[0]);
2104
2105 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
2106 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2107
2108 $this->setUser($this->students[0]);
2109 // Simulate a submission.
2110 $data = new stdClass();
2111 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2112 'text'=>'Student submission text',
2113 'format'=>FORMAT_MOODLE);
2114
2115 $notices = array();
2116 $assign->save_submission($data, $notices);
2117
2118 // Check that the submission text was saved.
2119 $output = $assign->view_student_summary($this->students[0], true);
2120 $this->assertContains('Student submission text', $output, 'Contains student submission text');
2121
2122 // Check that a teacher teacher with the extra capability can edit a students submission.
2123 $this->setUser($this->teachers[0]);
2124 $data = new stdClass();
2125 $data->userid = $this->students[0]->id;
2126 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2127 'text'=>'Teacher edited submission text',
2128 'format'=>FORMAT_MOODLE);
2129
2130 // Add the required capability.
2131 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
2132 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2133 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
2134 accesslib_clear_all_caches_for_unit_testing();
2135
2136 // Try to save the submission.
2137 $notices = array();
2138 $assign->save_submission($data, $notices);
2139
2140 // Check that the teacher can submit the students work.
2141 $data = new stdClass();
2142 $data->userid = $this->students[0]->id;
2143 $notices = array();
2144 $assign->submit_for_grading($data, $notices);
2145
2146 // Revert to draft so the student can edit it.
2147 $assign->revert_to_draft($this->students[0]->id);
2148
2149 $this->setUser($this->students[0]);
2150
2151 // Check that the submission text was saved.
2152 $output = $assign->view_student_summary($this->students[0], true);
2153 $this->assertContains('Teacher edited submission text', $output, 'Contains student submission text');
2154
2155 // Check that the student can submit their work.
2156 $data = new stdClass();
2157 $assign->submit_for_grading($data, $notices);
2158
2159 $output = $assign->view_student_summary($this->students[0], true);
2160 $this->assertNotContains(get_string('addsubmission', 'assign'), $output);
2161
2162 // Set to a default editing teacher who should not be able to edit this submission.
2163 $this->setUser($this->editingteachers[1]);
2164
2165 // Revert to draft so the submission is editable.
2166 $assign->revert_to_draft($this->students[0]->id);
2167
2168 $data = new stdClass();
2169 $data->userid = $this->students[0]->id;
2170 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2171 'text'=>'Teacher 2 edited submission text',
2172 'format'=>FORMAT_MOODLE);
2173
2174 $notices = array();
2175 $this->setExpectedException('moodle_exception');
2176 $assign->save_submission($data, $notices);
2177
2178 $sink->close();
2179 }
2180
9054c04d 2181 public function test_disable_submit_after_cutoff_date() {
2182 global $PAGE;
2183
2184 $this->setUser($this->editingteachers[0]);
2185 $now = time();
2186 $tomorrow = $now + 24*60*60;
2187 $lastweek = $now - 7*24*60*60;
2188 $yesterday = $now - 24*60*60;
2189
2190 $assign = $this->create_instance(array('duedate'=>$yesterday,
2191 'cutoffdate'=>$tomorrow,
2192 'assignsubmission_onlinetext_enabled'=>1));
2193 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2194
2195 // Student should be able to see an add submission button.
2196 $this->setUser($this->students[0]);
2197 $output = $assign->view_student_summary($this->students[0], true);
2198 $this->assertNotEquals(false, strpos($output, get_string('addsubmission', 'assign')));
2199
2200 // Add a submission but don't submit now.
2201 $submission = $assign->get_user_submission($this->students[0]->id, true);
2202 $data = new stdClass();
2203 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2204 'text'=>'Submission text',
2205 'format'=>FORMAT_MOODLE);
2206 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2207 $plugin->save($submission, $data);
2208
2209 // Create another instance with cut-off and due-date already passed.
2210 $this->setUser($this->editingteachers[0]);
2211 $now = time();
2212 $assign = $this->create_instance(array('duedate'=>$lastweek,
2213 'cutoffdate'=>$yesterday,
2214 'assignsubmission_onlinetext_enabled'=>1));
2215
2216 $this->setUser($this->students[0]);
2217 $output = $assign->view_student_summary($this->students[0], true);
2218 $this->assertNotContains($output, get_string('editsubmission', 'assign'),
2219 'Should not be able to edit after cutoff date.');
2220 $this->assertNotContains($output, get_string('submitassignment', 'assign'),
2221 'Should not be able to submit after cutoff date.');
2222 }
f159ad73 2223 /**
2224 * Testing for submission comment plugin settings
2225 */
2226 public function test_submission_comment_plugin_settings() {
2227 global $CFG;
2228
2229 $commentconfig = false;
2230 if (!empty($CFG->usecomments)) {
2231 $commentconfig = $CFG->usecomments;
2232 }
2233
2234 $CFG->usecomments = true;
2235 $assign = $this->create_instance();
2236 $plugin = $assign->get_submission_plugin_by_type('comments');
2237 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2238
2239 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
2240 $plugin = $assign->get_submission_plugin_by_type('comments');
2241 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2242
2243 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
2244 $plugin = $assign->get_submission_plugin_by_type('comments');
2245 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2246
2247 $CFG->usecomments = false;
2248 $assign = $this->create_instance();
2249 $plugin = $assign->get_submission_plugin_by_type('comments');
2250 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2251
2252 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 0));
2253 $plugin = $assign->get_submission_plugin_by_type('comments');
2254 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2255
2256 $assign = $this->create_instance(array('assignsubmission_comments_enabled' => 1));
2257 $plugin = $assign->get_submission_plugin_by_type('comments');
2258 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2259
2260 $CFG->usecomments = $commentconfig;
2261 }
2262
c7a73689
DW
2263 /**
2264 * Testing for comment inline settings
2265 */
2266 public function test_feedback_comment_commentinline() {
2267 global $CFG;
2268
2269 $sourcetext = "Hello!
2270
2271I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
2272
2273URL outside a tag: https://moodle.org/logo/logo-240x60.gif
2274Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
2275
2276External link 1:<img src='https://moodle.org/logo/logo-240x60.gif' alt='Moodle'/>
2277External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\"/>
2278Internal link 1:<img src='@@PLUGINFILE@@/logo-240x60.gif' alt='Moodle'/>
2279Internal link 2:<img alt=\"Moodle\" src=\"@@PLUGINFILE@@logo-240x60.gif\"/>
2280Anchor link 1:<a href=\"@@PLUGINFILE@@logo-240x60.gif\" alt=\"bananas\">Link text</a>
2281Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
2282";
2283
2284 // Note the internal images have been stripped and the html is purified (quotes fixed in this case).
2285 $filteredtext = "Hello!
2286
2287I'm writing to you from the Moodle Majlis in Muscat, Oman, where we just had several days of Moodle community goodness.
2288
2289URL outside a tag: https://moodle.org/logo/logo-240x60.gif
2290Plugin url outside a tag: @@PLUGINFILE@@/logo-240x60.gif
2291
2292External link 1:<img src=\"https://moodle.org/logo/logo-240x60.gif\" alt=\"Moodle\" />
2293External link 2:<img alt=\"Moodle\" src=\"https://moodle.org/logo/logo-240x60.gif\" />
2294Internal link 1:
2295Internal link 2:
2296Anchor link 1:Link text
2297Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
2298";
2299
2300 $this->setUser($this->editingteachers[0]);
2301 $params = array('assignsubmission_onlinetext_enabled' => 1,
2302 'assignfeedback_comments_enabled' => 1,
2303 'assignfeedback_comments_commentinline' => 1);
2304 $assign = $this->create_instance($params);
2305
2306 $this->setUser($this->students[0]);
2307 // Add a submission but don't submit now.
2308 $submission = $assign->get_user_submission($this->students[0]->id, true);
2309 $data = new stdClass();
2310
2311 // Test the internal link is stripped, but the external one is not.
2312 $data->onlinetext_editor = array('itemid'=>file_get_unused_draft_itemid(),
2313 'text'=>$sourcetext,
2314 'format'=>FORMAT_MOODLE);
2315
2316 $plugin = $assign->get_submission_plugin_by_type('onlinetext');
2317 $plugin->save($submission, $data);
2318
2319 $this->setUser($this->editingteachers[0]);
2320
2321 $data = new stdClass();
2322 require_once($CFG->dirroot . '/mod/assign/gradeform.php');
2323 $pagination = array('userid'=>$this->students[0]->id,
2324 'rownum'=>0,
2325 'last'=>true,
3fca6937 2326 'useridlistid' => $assign->get_useridlist_key_id(),
c7a73689
DW
2327 'attemptnumber'=>0);
2328 $formparams = array($assign, $data, $pagination);
2329 $mform = new mod_assign_grade_form(null, $formparams);
2330
2331 $this->assertEquals($filteredtext, $data->assignfeedbackcomments_editor['text']);
2332 }
2333
f159ad73 2334 /**
2335 * Testing for feedback comment plugin settings
2336 */
2337 public function test_feedback_plugin_settings() {
2338
2339 $assign = $this->create_instance();
2340 $plugin = $assign->get_feedback_plugin_by_type('comments');
2341 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2342
2343 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 0));
2344 $plugin = $assign->get_feedback_plugin_by_type('comments');
2345 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2346
2347 $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
2348 $plugin = $assign->get_feedback_plugin_by_type('comments');
2349 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2350 }
456d7bc7
RT
2351
2352 /**
2353 * Testing if gradebook feedback plugin is enabled.
2354 */
2355 public function test_is_gradebook_feedback_enabled() {
2356 $adminconfig = get_config('assign');
2357 $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
2358
2359 // Create assignment with gradebook feedback enabled and grade = 0.
2360 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 1, 'grades' => 0));
2361
2362 // Get gradebook feedback plugin.
2363 $gradebookplugintype = str_replace('assignfeedback_', '', $gradebookplugin);
2364 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
2365 $this->assertEquals(1, $plugin->is_enabled('enabled'));
2366 $this->assertEquals(1, $assign->is_gradebook_feedback_enabled());
2367
2368 // Create assignment with gradebook feedback disabled and grade = 0.
2369 $assign = $this->create_instance(array($gradebookplugin . '_enabled' => 0, 'grades' => 0));
2370 $plugin = $assign->get_feedback_plugin_by_type($gradebookplugintype);
2371 $this->assertEquals(0, $plugin->is_enabled('enabled'));
2372 }
57fbd5f9
DW
2373
2374 /**
2375 * Testing can_edit_submission
2376 */
2377 public function test_can_edit_submission() {
2378 global $PAGE, $DB;
2379 $this->create_extra_users();
2380
2381 $this->setAdminUser();
2382 // Create assignment (onlinetext).
2383 $assign = $this->create_instance(array('assignsubmission_onlinetext_enabled'=>1, 'submissiondrafts'=>1));
2384 $PAGE->set_url(new moodle_url('/mod/assign/view.php', array('id' => $assign->get_course_module()->id)));
2385
2386 // Check student can edit their own submission.
2387 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->students[0]->id));
2388 // Check student cannot edit others submission.
2389 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->students[1]->id));
2390
2391 // Check teacher cannot (by default) edit a students submission.
2392 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
2393
2394 // Add the required capability to edit a student submission.
2395 $roleid = create_role('Dummy role', 'dummyrole', 'dummy role description');
2396 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2397 role_assign($roleid, $this->teachers[0]->id, $assign->get_context()->id);
2398 accesslib_clear_all_caches_for_unit_testing();
2399 // Retest - should now have access.
2400 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->teachers[0]->id));
2401
2402 // Force create an assignment with SEPARATEGROUPS.
2403 $data = new stdClass();
2404 $data->courseid = $this->course->id;
2405 $data->name = 'Grouping';
2406 $groupingid = groups_create_grouping($data);
2407 groups_assign_grouping($groupingid, $this->groups[0]->id);
2408 groups_assign_grouping($groupingid, $this->groups[1]->id);
2409 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
2410
2411 // Add the capability to the new assignment for extra students 0 and 1.
2412 assign_capability('mod/assign:editothersubmission', CAP_ALLOW, $roleid, $assign->get_context()->id);
2413 role_assign($roleid, $this->extrastudents[0]->id, $assign->get_context()->id);
2414 role_assign($roleid, $this->extrastudents[1]->id, $assign->get_context()->id);
2415 accesslib_clear_all_caches_for_unit_testing();
2416
2417 // Verify the extra student does not have the capability to edit a submission not in their group.
2418 $this->assertFalse($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[1]->id));
2419 // Verify the extra student does have the capability to edit a submission in their group.
2420 $this->assertTrue($assign->can_edit_submission($this->students[0]->id, $this->extrastudents[0]->id));
2421
2422 }
323f221b
MH
2423
2424 /**
2425 * Test if the view blind details capability works
2426 */
2427 public function test_can_view_blind_details() {
2428 global $PAGE, $DB;
2429 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
2430 $managerrole = $DB->get_record('role', array('shortname' => 'manager'));
2431
2432 $student = $this->students[0];// Get a student user.
2433 // Create a teacher. Shouldn't be able to view blind marking ID.
2434 $teacher = $this->getDataGenerator()->create_user();
2435
2436 $this->getDataGenerator()->enrol_user($teacher->id,
2437 $this->course->id,
2438 $teacherrole->id);
2439
2440 // Create a manager.. Should be able to view blind marking ID.
2441 $manager = $this->getDataGenerator()->create_user();
e28d6b29
MG
2442 $this->getDataGenerator()->enrol_user($manager->id,
2443 $this->course->id,
323f221b
MH
2444 $managerrole->id);
2445
2446 // Generate blind marking assignment.
e28d6b29 2447 $assign = $this->create_instance(array('blindmarking' => 1));
323f221b
MH
2448 $this->assertEquals(true, $assign->is_blind_marking());
2449
2450 // Test student names are hidden to teacher.
e28d6b29
MG
2451 $this->setUser($teacher);
2452 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
2453 $output = $assign->get_renderer()->render($gradingtable);
323f221b
MH
2454 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign'))); // "Participant" is somewhere on the page.
2455 $this->assertEquals(false, strpos($output, fullname($student))); // Students full name doesn't appear.
2456
2457 // Test student names are visible to manager.
e28d6b29
MG
2458 $this->setUser($manager);
2459 $gradingtable = new assign_grading_table($assign, 1, '', 0, true);
2460 $output = $assign->get_renderer()->render($gradingtable);
59e95487
MH
2461 $this->assertEquals(true, strpos($output, get_string('hiddenuser', 'assign')));
2462 $this->assertEquals(true, strpos($output, fullname($student)));
323f221b 2463 }
6d6e297b
DM
2464
2465 /**
2466 * Testing get_shared_group_members
2467 */
2468 public function test_get_shared_group_members() {
2469 $this->create_extra_users();
2470 $this->setAdminUser();
2471
2472 // Force create an assignment with SEPARATEGROUPS.
2473 $data = new stdClass();
2474 $data->courseid = $this->course->id;
2475 $data->name = 'Grouping';
2476 $groupingid = groups_create_grouping($data);
2477 groups_assign_grouping($groupingid, $this->groups[0]->id);
2478 groups_assign_grouping($groupingid, $this->groups[1]->id);
2479 $assign = $this->create_instance(array('groupingid' => $groupingid, 'groupmode' => SEPARATEGROUPS));
2480 $cm = $assign->get_course_module();
2481
2482 // Add the capability to access allgroups.
2483 $roleid = create_role('Access all groups role', 'accessallgroupsrole', '');
2484 assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $roleid, $assign->get_context()->id);
2485 role_assign($roleid, $this->extrastudents[3]->id, $assign->get_context()->id);
2486 accesslib_clear_all_caches_for_unit_testing();
2487
2488 // Get shared group members for students 0 and 1.
2489 $groupmembers = array();
2490 $groupmembers[0] = $assign->get_shared_group_members($cm, $this->students[0]->id);
2491 $groupmembers[1] = $assign->get_shared_group_members($cm, $this->students[1]->id);
2492
2493 // They should share groups with extrastudents 0 and 1.
2494 $this->assertTrue(in_array($this->extrastudents[0]->id, $groupmembers[0]));
2495 $this->assertFalse(in_array($this->extrastudents[0]->id, $groupmembers[1]));
2496 $this->assertTrue(in_array($this->extrastudents[1]->id, $groupmembers[1]));
2497 $this->assertFalse(in_array($this->extrastudents[1]->id, $groupmembers[0]));
2498
2499 // Lists of group members for students and extrastudents should be the same.
2500 $this->assertEquals($groupmembers[0], $assign->get_shared_group_members($cm, $this->extrastudents[0]->id));
2501 $this->assertEquals($groupmembers[1], $assign->get_shared_group_members($cm, $this->extrastudents[1]->id));
2502
2503 // Get all group members for extrastudent 3 wich can access all groups.
2504 $allgroupmembers = $assign->get_shared_group_members($cm, $this->extrastudents[3]->id);
2505
2506 // Extrastudent 3 should see students 0 and 1, extrastudent 0 and 1.
2507 $this->assertTrue(in_array($this->students[0]->id, $allgroupmembers));
2508 $this->assertTrue(in_array($this->students[1]->id, $allgroupmembers));
2509 $this->assertTrue(in_array($this->extrastudents[0]->id, $allgroupmembers));
2510 $this->assertTrue(in_array($this->extrastudents[1]->id , $allgroupmembers));
2511 }
47f48152 2512
92ea1fa0
JL
2513 /**
2514 * Test get plugins file areas
2515 */
2516 public function test_get_plugins_file_areas() {
2517 $this->setUser($this->editingteachers[0]);
2518 $assign = $this->create_instance();
2519
2520 // Test that all the submission and feedback plugins are returning the expected file aras.
2521 $usingfilearea = 0;
11ee4f71 2522 $coreplugins = core_plugin_manager::standard_plugins_list('assignsubmission');
92ea1fa0
JL
2523 foreach ($assign->get_submission_plugins() as $plugin) {
2524 $type = $plugin->get_type();
11ee4f71
AO
2525 if (!in_array($type, $coreplugins)) {
2526 continue;
2527 }
92ea1fa0
JL
2528 $fileareas = $plugin->get_file_areas();
2529
2530 if ($type == 'onlinetext') {
2531 $this->assertEquals(array('submissions_onlinetext' => 'Online text'), $fileareas);
2532 $usingfilearea++;
2533 } else if ($type == 'file') {
2534 $this->assertEquals(array('submission_files' => 'File submissions'), $fileareas);
2535 $usingfilearea++;
2536 } else {
2537 $this->assertEmpty($fileareas);
2538 }
2539 }
2540 $this->assertEquals(2, $usingfilearea);
2541
2542 $usingfilearea = 0;
11ee4f71 2543 $coreplugins = core_plugin_manager::standard_plugins_list('assignfeedback');
92ea1fa0
JL
2544 foreach ($assign->get_feedback_plugins() as $plugin) {
2545 $type = $plugin->get_type();
11ee4f71
AO
2546 if (!in_array($type, $coreplugins)) {
2547 continue;
2548 }
92ea1fa0
JL
2549 $fileareas = $plugin->get_file_areas();
2550
2551 if ($type == 'editpdf') {
2552 $this->assertEquals(array('download' => 'Annotate PDF'), $fileareas);
2553 $usingfilearea++;
2554 } else if ($type == 'file') {
2555 $this->assertEquals(array('feedback_files' => 'Feedback files'), $fileareas);
2556 $usingfilearea++;
2557 } else {
2558 $this->assertEmpty($fileareas);
2559 }
2560 }
2561 $this->assertEquals(2, $usingfilearea);
2562 }
2563
002864cc
EM
2564 /**
2565 * Test the quicksave grades processor
2566 */
2567 public function test_process_save_quick_grades() {
2568 $this->editingteachers[0]->ignoresesskey = true;
2569 $this->setUser($this->editingteachers[0]);
2570
2571 $assign = $this->create_instance(array('attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL));
2572
2573 // Initially grade the user.
2574 $grade = $assign->get_user_grade($this->students[0]->id, false);
2575 if (!$grade) {
2576 $grade = new stdClass();
2577 $grade->attemptnumber = '';
2578 $grade->timemodified = '';
2579 }
2580 $data = array(
2581 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2582 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2583 'quickgrade_' . $this->students[0]->id => '60.0'
2584 );
2585 $result = $assign->testable_process_save_quick_grades($data);
2586 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2587 $grade = $assign->get_user_grade($this->students[0]->id, false);
2588 $this->assertEquals('60.0', $grade->grade);
2589
2590 // Attempt to grade with a past attempts grade info.
2591 $assign->testable_process_add_attempt($this->students[0]->id);
2592 $data = array(
2593 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2594 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2595 'quickgrade_' . $this->students[0]->id => '50.0'
2596 );
2597 $result = $assign->testable_process_save_quick_grades($data);
2598 $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
2599 $grade = $assign->get_user_grade($this->students[0]->id, false);
2600 $this->assertFalse($grade);
2601
2602 // Attempt to grade a the attempt.
2603 $submission = $assign->get_user_submission($this->students[0]->id, false);
2604 $data = array(
2605 'grademodified_' . $this->students[0]->id => '',
2606 'gradeattempt_' . $this->students[0]->id => $submission->attemptnumber,
2607 'quickgrade_' . $this->students[0]->id => '40.0'
2608 );
2609 $result = $assign->testable_process_save_quick_grades($data);
2610 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2611 $grade = $assign->get_user_grade($this->students[0]->id, false);
2612 $this->assertEquals('40.0', $grade->grade);
2613
2614 // Catch grade update conflicts.
2615 // Save old data for later.
2616 $pastdata = $data;
2617 // Update the grade the 'good' way.
2618 $data = array(
2619 'grademodified_' . $this->students[0]->id => $grade->timemodified,
2620 'gradeattempt_' . $this->students[0]->id => $grade->attemptnumber,
2621 'quickgrade_' . $this->students[0]->id => '30.0'
2622 );
2623 $result = $assign->testable_process_save_quick_grades($data);
2624 $this->assertContains(get_string('quickgradingchangessaved', 'assign'), $result);
2625 $grade = $assign->get_user_grade($this->students[0]->id, false);
2626 $this->assertEquals('30.0', $grade->grade);
2627
2628 // Now update using 'old' data. Should fail.
2629 $result = $assign->testable_process_save_quick_grades($pastdata);
2630 $this->assertContains(get_string('errorrecordmodified', 'assign'), $result);
2631 $grade = $assign->get_user_grade($this->students[0]->id, false);
2632 $this->assertEquals('30.0', $grade->grade);
2633 }
0cf8082a
AG
2634
2635 /**
2636 * Test updating activity completion when submitting an assessment.
2637 */
2638 public function test_update_activity_completion_records_solitary_submission() {
2639 $assign = $this->create_instance(array('grade' => 100,
2640 'completion' => COMPLETION_TRACKING_AUTOMATIC,
2641 'requireallteammemberssubmit' => 0));
2642
2643 $cm = $assign->get_course_module();
2644
2645 $student = $this->students[0];
2646 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
2647
2648 $this->setUser($student);
2649
2650 // Simulate a submission.
2651 $data = new stdClass();
2652 $data->onlinetext_editor = array(
2653 'itemid' => file_get_unused_draft_itemid(),
2654 'text' => 'Student submission text',
2655 'format' => FORMAT_MOODLE
2656 );
2657 $completion = new completion_info($this->course);
2658
2659 $notices = array();
2660 $assign->save_submission($data, $notices);
2661
2662 $submission = $assign->get_user_submission($student->id, true);
2663
2664 // Check that completion is not met yet.
2665 $completiondata = $completion->get_data($cm, false, $student->id);
2666 $this->assertEquals(0, $completiondata->completionstate);
2667 $assign->testable_update_activity_completion_records(0, 0, $submission,
2668 $student->id, COMPLETION_COMPLETE, $completion);
2669 // Completion should now be met.
2670 $completiondata = $completion->get_data($cm, false, $student->id);
2671 $this->assertEquals(1, $completiondata->completionstate);
2672 }
2673
2674 /**
2675 * Test updating activity completion when submitting an assessment.
2676 */
2677 public function test_update_activity_completion_records_team_submission() {
2678 $assign = $this->create_instance(array('grade' => 100,
2679 'completion' => COMPLETION_TRACKING_AUTOMATIC,
2680 'teamsubmission' => 1));
2681
2682 $cm = $assign->get_course_module();
2683
2684 $student1 = $this->students[0];
2685 $student2 = $this->students[1];
2686 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
2687
2688 // Put both users into a group.
2689 $group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
2690 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student1->id));
2691 $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $student2->id));
2692
2693 $this->setUser($student1);
2694
2695 // Simulate a submission.
2696 $data = new stdClass();
2697 $data->onlinetext_editor = array(
2698 'itemid' => file_get_unused_draft_itemid(),
2699 'text' => 'Student submission text',
2700 'format' => FORMAT_MOODLE
2701 );
2702 $completion = new completion_info($this->course);
2703
2704 $notices = array();
2705 $assign->save_submission($data, $notices);
2706
2707 $submission = $assign->get_user_submission($student1->id, true);
2708 $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
2709 $submission->groupid = $group1->id;
2710
2711 // Check that completion is not met yet.
2712 $completiondata = $completion->get_data($cm, false, $student1->id);
2713 $this->assertEquals(0, $completiondata->completionstate);
2714 $completiondata = $completion->get_data($cm, false, $student2->id);
2715 $this->assertEquals(0, $completiondata->completionstate);
2716 $assign->testable_update_activity_completion_records(1, 0, $submission, $student1->id,
2717 COMPLETION_COMPLETE, $completion);
2718 // Completion should now be met.
2719 $completiondata = $completion->get_data($cm, false, $student1->id);
2720 $this->assertEquals(1, $completiondata->completionstate);
2721 $completiondata = $completion->get_data($cm, false, $student2->id);
2722 $this->assertEquals(1, $completiondata->completionstate);
2723 }
002864cc 2724}