Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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   * User grade report functions unit tests
  19   *
  20   * @package    gradereport_user
  21   * @category   external
  22   * @copyright  2015 Juan Leyva <juan@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  
  30  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  31  require_once($CFG->dirroot . '/grade/report/user/externallib.php');
  32  
  33  /**
  34   * User grade report functions unit tests
  35   *
  36   * @package    gradereport_user
  37   * @category   external
  38   * @copyright  2015 Juan Leyva <juan@moodle.com>
  39   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  40   */
  41  class gradereport_user_externallib_testcase extends externallib_advanced_testcase {
  42  
  43      /**
  44       * Loads some data to be used by the different tests
  45       * @param  int $s1grade Student 1 grade
  46       * @param  int $s2grade Student 2 grade
  47       * @return array          Course and users instances
  48       */
  49      private function load_data($s1grade, $s2grade) {
  50          global $DB;
  51  
  52          $course = $this->getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1));
  53  
  54          $studentrole = $DB->get_record('role', array('shortname' => 'student'));
  55          $student1 = $this->getDataGenerator()->create_user(array('idnumber' => 'testidnumber'));
  56          $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
  57  
  58          $student2 = $this->getDataGenerator()->create_user();
  59          $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
  60  
  61          $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
  62          $teacher = $this->getDataGenerator()->create_user();
  63          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
  64  
  65          $context = context_course::instance($course->id);
  66          assign_capability('moodle/site:accessallgroups', CAP_PROHIBIT, $teacherrole->id, $context);
  67          accesslib_clear_all_caches_for_unit_testing();
  68  
  69          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
  70          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
  71          groups_add_member($group1->id, $student1->id);
  72          groups_add_member($group1->id, $teacher->id);
  73          groups_add_member($group2->id, $student2->id);
  74  
  75          $assignment = $this->getDataGenerator()->create_module('assign', array('name' => "Test assign", 'course' => $course->id));
  76          $modcontext = get_coursemodule_from_instance('assign', $assignment->id, $course->id);
  77          $assignment->cmidnumber = $modcontext->id;
  78  
  79          $student1grade = array('userid' => $student1->id, 'rawgrade' => $s1grade, 'idnumber' => 'testidnumber1');
  80          $student2grade = array('userid' => $student2->id, 'rawgrade' => $s2grade, 'idnumber' => 'testidnumber2');
  81          $studentgrades = array($student1->id => $student1grade, $student2->id => $student2grade);
  82          assign_grade_item_update($assignment, $studentgrades);
  83  
  84          return array($course, $teacher, $student1, $student2, $assignment);
  85      }
  86  
  87      /**
  88       * Test get_grades_table function case teacher
  89       */
  90      public function test_get_grades_table_teacher() {
  91  
  92          $this->resetAfterTest(true);
  93  
  94          $s1grade = 80;
  95          $s2grade = 60;
  96  
  97          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
  98  
  99          // A teacher must see all student grades (in their group only).
 100          $this->setUser($teacher);
 101  
 102          $studentgrades = gradereport_user_external::get_grades_table($course->id);
 103          $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grades_table_returns(), $studentgrades);
 104  
 105          // No warnings returned.
 106          $this->assertCount(0, $studentgrades['warnings']);
 107  
 108          // Check that only grades for the student in the teacher group are returned.
 109          $this->assertCount(1, $studentgrades['tables']);
 110  
 111          // Read returned grades.
 112          $studentreturnedgrades = array();
 113          $studentreturnedgrades[$studentgrades['tables'][0]['userid']] =
 114              (int) $studentgrades['tables'][0]['tabledata'][1]['grade']['content'];
 115  
 116          $this->assertEquals($s1grade, $studentreturnedgrades[$student1->id]);
 117      }
 118  
 119      /**
 120       * Test get_grades_table function case student
 121       */
 122      public function test_get_grades_table_student() {
 123          global $CFG, $DB;
 124  
 125          $this->resetAfterTest(true);
 126  
 127          $s1grade = 80;
 128          $s2grade = 60;
 129  
 130          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 131  
 132          // A user can see his own grades.
 133          $this->setUser($student1);
 134          $studentgrade = gradereport_user_external::get_grades_table($course->id, $student1->id);
 135          $studentgrade = external_api::clean_returnvalue(gradereport_user_external::get_grades_table_returns(), $studentgrade);
 136  
 137          // No warnings returned.
 138          $this->assertTrue(count($studentgrade['warnings']) == 0);
 139  
 140          $this->assertTrue(count($studentgrade['tables']) == 1);
 141          $student1returnedgrade = (int) $studentgrade['tables'][0]['tabledata'][1]['grade']['content'];
 142          $this->assertEquals($s1grade, $student1returnedgrade);
 143  
 144      }
 145  
 146      /**
 147       * Test get_grades_table function case incorrect permissions
 148       */
 149      public function test_get_grades_table_permissions() {
 150          global $CFG, $DB;
 151  
 152          $this->resetAfterTest(true);
 153  
 154          $s1grade = 80;
 155          $s2grade = 60;
 156  
 157          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 158  
 159          $this->setUser($student2);
 160  
 161          try {
 162              $studentgrade = gradereport_user_external::get_grades_table($course->id, $student1->id);
 163              $this->fail('Exception expected due to not perissions to view other user grades.');
 164          } catch (moodle_exception $e) {
 165              $this->assertEquals('notingroup', $e->errorcode);
 166          }
 167      }
 168  
 169      /**
 170       * Test view_grade_report function
 171       */
 172      public function test_view_grade_report() {
 173          global $USER;
 174  
 175          $this->resetAfterTest(true);
 176  
 177          $s1grade = 80;
 178          $s2grade = 60;
 179          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 180  
 181          // Redirect events to the sink, so we can recover them later.
 182          $sink = $this->redirectEvents();
 183  
 184          $this->setUser($student1);
 185          $result = gradereport_user_external::view_grade_report($course->id);
 186          $result = external_api::clean_returnvalue(gradereport_user_external::view_grade_report_returns(), $result);
 187          $events = $sink->get_events();
 188          $this->assertCount(1, $events);
 189          $event = reset($events);
 190  
 191          // Check the event details are correct.
 192          $this->assertInstanceOf('\gradereport_user\event\grade_report_viewed', $event);
 193          $this->assertEquals(context_course::instance($course->id), $event->get_context());
 194          $this->assertEquals($USER->id, $event->get_data()['relateduserid']);
 195  
 196          $this->setUser($teacher);
 197          $result = gradereport_user_external::view_grade_report($course->id, $student1->id);
 198          $result = external_api::clean_returnvalue(gradereport_user_external::view_grade_report_returns(), $result);
 199          $events = $sink->get_events();
 200          $event = reset($events);
 201          $sink->close();
 202  
 203          // Check the event details are correct.
 204          $this->assertInstanceOf('\gradereport_user\event\grade_report_viewed', $event);
 205          $this->assertEquals(context_course::instance($course->id), $event->get_context());
 206          $this->assertEquals($student1->id, $event->get_data()['relateduserid']);
 207  
 208          $this->setUser($student2);
 209          try {
 210              $studentgrade = gradereport_user_external::view_grade_report($course->id, $student1->id);
 211              $this->fail('Exception expected due to not permissions to view other user grades.');
 212          } catch (moodle_exception $e) {
 213              $this->assertEquals('nopermissiontoviewgrades', $e->errorcode);
 214          }
 215      }
 216  
 217      /**
 218       * Test get_grades_items function case teacher
 219       */
 220      public function test_get_grade_items_teacher() {
 221  
 222          $this->resetAfterTest(true);
 223  
 224          $s1grade = 80;
 225          $s2grade = 60;
 226  
 227          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 228  
 229          // A teacher must see all student grades (in their group only).
 230          $this->setUser($teacher);
 231  
 232          grade_set_setting($course->id, 'report_user_showrank', 1);
 233          grade_set_setting($course->id, 'report_user_showpercentage', 1);
 234          grade_set_setting($course->id, 'report_user_showhiddenitems', 1);
 235          grade_set_setting($course->id, 'report_user_showgrade', 1);
 236          grade_set_setting($course->id, 'report_user_showfeedback', 1);
 237          grade_set_setting($course->id, 'report_user_showweight', 1);
 238          grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
 239          grade_set_setting($course->id, 'report_user_showlettergrade', 1);
 240          grade_set_setting($course->id, 'report_user_showaverage', 1);
 241  
 242          $studentgrades = gradereport_user_external::get_grade_items($course->id);
 243          $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
 244          // No warnings returned.
 245          $this->assertCount(0, $studentgrades['warnings']);
 246  
 247          // Check that only grades for the student in the teacher group are returned.
 248          $this->assertCount(1, $studentgrades['usergrades']);
 249          $this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
 250  
 251          $this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
 252          $this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
 253          // Module grades.
 254          $this->assertEquals($assignment->name, $studentgrades['usergrades'][0]['gradeitems'][0]['itemname']);
 255          $this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
 256          $this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
 257          $this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
 258          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['locked']);
 259          $this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
 260          $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
 261          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
 262          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
 263          $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
 264          $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
 265          $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
 266          $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
 267          $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
 268          $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
 269          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
 270          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
 271          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
 272          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
 273          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
 274          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
 275          $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
 276          $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
 277          $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
 278          $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
 279  
 280          // Course grades.
 281          $this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][1]['itemtype']);
 282          $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][1]['graderaw']);
 283          $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][1]['gradeformatted']);
 284          $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][1]['grademin']);
 285          $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][1]['grademax']);
 286          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['locked']);
 287          $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][1]['rangeformatted']);
 288          $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][1]['percentageformatted']);
 289          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][1]['feedback']);
 290          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradehiddenbydate']);
 291          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeneedsupdate']);
 292          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeishidden']);
 293          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeislocked']);
 294          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][1]['gradeisoverridden']);
 295          $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][1]['lettergradeformatted']);
 296          $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][1]['rank']);
 297          $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][1]['numusers']);
 298          $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][1]['averageformatted']);
 299  
 300          // Now, override and lock a grade.
 301          $gradegrade = grade_grade::fetch(['itemid' => $studentgrades['usergrades'][0]['gradeitems'][0]['id'],
 302              'userid' => $studentgrades['usergrades'][0]['userid']]);
 303          $gradegrade->set_overridden(true);
 304          $gradegrade->set_locked(1);
 305  
 306          $studentgrades = gradereport_user_external::get_grade_items($course->id);
 307          $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
 308          // No warnings returned.
 309          $this->assertCount(0, $studentgrades['warnings']);
 310  
 311          // Module grades.
 312          $this->assertTrue($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
 313          $this->assertTrue($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
 314      }
 315  
 316      /**
 317       * Test get_grades_items function case student
 318       */
 319      public function test_get_grade_items_student() {
 320  
 321          $this->resetAfterTest(true);
 322  
 323          $s1grade = 80;
 324          $s2grade = 60;
 325  
 326          list($course, $teacher, $student1, $student2, $assignment) = $this->load_data($s1grade, $s2grade);
 327  
 328          grade_set_setting($course->id, 'report_user_showrank', 1);
 329          grade_set_setting($course->id, 'report_user_showpercentage', 1);
 330          grade_set_setting($course->id, 'report_user_showgrade', 1);
 331          grade_set_setting($course->id, 'report_user_showfeedback', 1);
 332          grade_set_setting($course->id, 'report_user_showweight', 1);
 333          grade_set_setting($course->id, 'report_user_showcontributiontocoursetotal', 1);
 334          grade_set_setting($course->id, 'report_user_showlettergrade', 1);
 335          grade_set_setting($course->id, 'report_user_showaverage', 1);
 336  
 337          $this->setUser($student1);
 338  
 339          $studentgrades = gradereport_user_external::get_grade_items($course->id, $student1->id);
 340          $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
 341          // No warnings returned.
 342          $this->assertCount(0, $studentgrades['warnings']);
 343  
 344          // Check that only grades for the student in the teacher group are returned.
 345          $this->assertCount(1, $studentgrades['usergrades']);
 346          $this->assertCount(2, $studentgrades['usergrades'][0]['gradeitems']);
 347  
 348          $this->assertEquals($course->id, $studentgrades['usergrades'][0]['courseid']);
 349          $this->assertEquals($student1->id, $studentgrades['usergrades'][0]['userid']);
 350          $this->assertEquals($student1->idnumber, $studentgrades['usergrades'][0]['useridnumber']);
 351          $this->assertEquals($assignment->name, $studentgrades['usergrades'][0]['gradeitems'][0]['itemname']);
 352          $this->assertEquals('mod', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
 353          $this->assertEquals('assign', $studentgrades['usergrades'][0]['gradeitems'][0]['itemmodule']);
 354          $this->assertEquals($assignment->id, $studentgrades['usergrades'][0]['gradeitems'][0]['iteminstance']);
 355          $this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['locked']);
 356          $this->assertEquals($assignment->cmidnumber, $studentgrades['usergrades'][0]['gradeitems'][0]['cmid']);
 357          $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['itemnumber']);
 358          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['outcomeid']);
 359          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['scaleid']);
 360          $this->assertEquals(80, $studentgrades['usergrades'][0]['gradeitems'][0]['graderaw']);
 361          $this->assertEquals('80.00', $studentgrades['usergrades'][0]['gradeitems'][0]['gradeformatted']);
 362          $this->assertEquals(0, $studentgrades['usergrades'][0]['gradeitems'][0]['grademin']);
 363          $this->assertEquals(100, $studentgrades['usergrades'][0]['gradeitems'][0]['grademax']);
 364          $this->assertEquals('0&ndash;100', $studentgrades['usergrades'][0]['gradeitems'][0]['rangeformatted']);
 365          $this->assertEquals('80.00 %', $studentgrades['usergrades'][0]['gradeitems'][0]['percentageformatted']);
 366          $this->assertEmpty($studentgrades['usergrades'][0]['gradeitems'][0]['feedback']);
 367          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradehiddenbydate']);
 368          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeneedsupdate']);
 369          $this->assertFalse($studentgrades['usergrades'][0]['gradeitems'][0]['gradeishidden']);
 370          $this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['gradeislocked']);
 371          $this->assertNull($studentgrades['usergrades'][0]['gradeitems'][0]['gradeisoverridden']);
 372          $this->assertEquals('B-', $studentgrades['usergrades'][0]['gradeitems'][0]['lettergradeformatted']);
 373          $this->assertEquals(1, $studentgrades['usergrades'][0]['gradeitems'][0]['rank']);
 374          $this->assertEquals(2, $studentgrades['usergrades'][0]['gradeitems'][0]['numusers']);
 375          $this->assertEquals(70, $studentgrades['usergrades'][0]['gradeitems'][0]['averageformatted']);
 376  
 377          // Check that the idnumber for assignment grades is equal to the cmid.
 378          $this->assertEquals((string) $studentgrades['usergrades'][0]['gradeitems'][0]['cmid'],
 379              $studentgrades['usergrades'][0]['gradeitems'][0]['idnumber']);
 380  
 381          // Hide one grade for the user.
 382          $gradegrade = new grade_grade(array('userid' => $student1->id,
 383                                          'itemid' => $studentgrades['usergrades'][0]['gradeitems'][0]['id']), true);
 384          $gradegrade->set_hidden(1);
 385          $studentgrades = gradereport_user_external::get_grade_items($course->id, $student1->id);
 386          $studentgrades = external_api::clean_returnvalue(gradereport_user_external::get_grade_items_returns(), $studentgrades);
 387  
 388          // Check we get only the course final grade.
 389          $this->assertCount(1, $studentgrades['usergrades']);
 390          $this->assertCount(1, $studentgrades['usergrades'][0]['gradeitems']);
 391          $this->assertEquals('course', $studentgrades['usergrades'][0]['gradeitems'][0]['itemtype']);
 392      }
 393  
 394  }