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