[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/assign/tests/ -> locallib_test.php (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1