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