Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   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  namespace core;
  18  
  19  use core_grading_external;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  global $CFG;
  24  
  25  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  26  
  27  /**
  28   * Unit tests for the grading API defined in core_grading_external class.
  29   *
  30   * @package core
  31   * @category test
  32   * @copyright 2013 Paul Charsley
  33   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class grading_external_test extends \externallib_advanced_testcase {
  36  
  37      /**
  38       * Test get_definitions
  39       */
  40      public function test_get_definitions() {
  41          global $DB, $CFG, $USER;
  42  
  43          $this->resetAfterTest(true);
  44          // Create a course and assignment.
  45          $coursedata['idnumber'] = 'idnumbercourse';
  46          $coursedata['fullname'] = 'Lightwork Course';
  47          $coursedata['summary'] = 'Lightwork Course description';
  48          $coursedata['summaryformat'] = FORMAT_MOODLE;
  49          $course = self::getDataGenerator()->create_course($coursedata);
  50  
  51          $assigndata['course'] = $course->id;
  52          $assigndata['name'] = 'lightwork assignment';
  53  
  54          $cm = self::getDataGenerator()->create_module('assign', $assigndata);
  55  
  56          // Create manual enrolment record.
  57          $manualenroldata['enrol'] = 'manual';
  58          $manualenroldata['status'] = 0;
  59          $manualenroldata['courseid'] = $course->id;
  60          $enrolid = $DB->insert_record('enrol', $manualenroldata);
  61  
  62          // Create a teacher and give them capabilities.
  63          $coursecontext = \context_course::instance($course->id);
  64          $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $coursecontext->id, 3);
  65          $modulecontext = \context_module::instance($cm->cmid);
  66          $this->assignUserCapability('mod/assign:grade', $modulecontext->id, $roleid);
  67  
  68          // Create the teacher's enrolment record.
  69          $userenrolmentdata['status'] = 0;
  70          $userenrolmentdata['enrolid'] = $enrolid;
  71          $userenrolmentdata['userid'] = $USER->id;
  72          $DB->insert_record('user_enrolments', $userenrolmentdata);
  73  
  74          // Create a grading area.
  75          $gradingarea = array(
  76              'contextid' => $modulecontext->id,
  77              'component' => 'mod_assign',
  78              'areaname' => 'submissions',
  79              'activemethod' => 'rubric'
  80          );
  81          $areaid = $DB->insert_record('grading_areas', $gradingarea);
  82  
  83          // Create a rubric grading definition.
  84          $rubricdefinition = array (
  85              'areaid' => $areaid,
  86              'method' => 'rubric',
  87              'name' => 'test',
  88              'status' => 20,
  89              'copiedfromid' => 1,
  90              'timecreated' => 1,
  91              'usercreated' => $USER->id,
  92              'timemodified' => 1,
  93              'usermodified' => $USER->id,
  94              'timecopied' => 0
  95          );
  96          $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
  97  
  98          // Create a criterion with levels.
  99          $rubriccriteria1 = array (
 100              'definitionid' => $definitionid,
 101              'sortorder' => 1,
 102              'description' => 'Demonstrate an understanding of disease control',
 103              'descriptionformat' => 0
 104          );
 105          $criterionid1 = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria1);
 106          $rubriclevel1 = array (
 107              'criterionid' => $criterionid1,
 108              'score' => 5,
 109              'definition' => 'pass',
 110              'definitionformat' => 0
 111          );
 112          $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
 113          $rubriclevel2 = array (
 114              'criterionid' => $criterionid1,
 115              'score' => 10,
 116              'definition' => 'excellent',
 117              'definitionformat' => 0
 118          );
 119          $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
 120  
 121          // Create a second criterion with levels.
 122          $rubriccriteria2 = array (
 123              'definitionid' => $definitionid,
 124              'sortorder' => 2,
 125              'description' => 'Demonstrate an understanding of brucellosis',
 126              'descriptionformat' => 0
 127          );
 128          $criterionid2 = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria2);
 129          $rubriclevel1 = array (
 130              'criterionid' => $criterionid2,
 131              'score' => 5,
 132              'definition' => 'pass',
 133              'definitionformat' => 0
 134          );
 135          $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
 136          $rubriclevel2 = array (
 137              'criterionid' => $criterionid2,
 138              'score' => 10,
 139              'definition' => 'excellent',
 140              'definitionformat' => 0
 141          );
 142          $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
 143  
 144          // Call the external function.
 145          $cmids = array ($cm->cmid);
 146          $areaname = 'submissions';
 147          $result = core_grading_external::get_definitions($cmids, $areaname);
 148          $result = \external_api::clean_returnvalue(core_grading_external::get_definitions_returns(), $result);
 149  
 150          $this->assertEquals(1, count($result['areas']));
 151          $this->assertEquals(1, count($result['areas'][0]['definitions']));
 152          $definition = $result['areas'][0]['definitions'][0];
 153  
 154          $this->assertEquals($rubricdefinition['method'], $definition['method']);
 155          $this->assertEquals($USER->id, $definition['usercreated']);
 156  
 157          require_once("$CFG->dirroot/grade/grading/lib.php");
 158          require_once($CFG->dirroot.'/grade/grading/form/'.$rubricdefinition['method'].'/lib.php');
 159  
 160          $gradingmanager = get_grading_manager($areaid);
 161  
 162          $this->assertEquals(1, count($definition[$rubricdefinition['method']]));
 163  
 164          $rubricdetails = $definition[$rubricdefinition['method']];
 165          $details = call_user_func('gradingform_'.$rubricdefinition['method'].'_controller::get_external_definition_details');
 166  
 167          $this->assertEquals(2, count($rubricdetails[key($details)]));
 168  
 169          $found = false;
 170          foreach ($rubricdetails[key($details)] as $criterion) {
 171              if ($criterion['id'] == $criterionid1) {
 172                  $this->assertEquals($rubriccriteria1['description'], $criterion['description']);
 173                  $this->assertEquals(2, count($criterion['levels']));
 174                  $found = true;
 175                  break;
 176              }
 177          }
 178          $this->assertTrue($found);
 179      }
 180  
 181      /**
 182       * Test get_gradingform_instances
 183       */
 184      public function test_get_gradingform_instances() {
 185          global $DB, $USER;
 186  
 187          $this->resetAfterTest(true);
 188          // Create a course and assignment.
 189          $coursedata['idnumber'] = 'idnumbercourse';
 190          $coursedata['fullname'] = 'Lightwork Course';
 191          $coursedata['summary'] = 'Lightwork Course description';
 192          $coursedata['summaryformat'] = FORMAT_MOODLE;
 193          $course = self::getDataGenerator()->create_course($coursedata);
 194  
 195          $assigndata['course'] = $course->id;
 196          $assigndata['name'] = 'lightwork assignment';
 197  
 198          $assign = self::getDataGenerator()->create_module('assign', $assigndata);
 199  
 200          // Create manual enrolment record.
 201          $manualenroldata['enrol'] = 'manual';
 202          $manualenroldata['status'] = 0;
 203          $manualenroldata['courseid'] = $course->id;
 204          $enrolid = $DB->insert_record('enrol', $manualenroldata);
 205  
 206          // Create a teacher and give them capabilities.
 207          $coursecontext = \context_course::instance($course->id);
 208          $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $coursecontext->id, 3);
 209          $modulecontext = \context_module::instance($assign->cmid);
 210          $this->assignUserCapability('mod/assign:grade', $modulecontext->id, $roleid);
 211  
 212          // Create the teacher's enrolment record.
 213          $userenrolmentdata['status'] = 0;
 214          $userenrolmentdata['enrolid'] = $enrolid;
 215          $userenrolmentdata['userid'] = $USER->id;
 216          $DB->insert_record('user_enrolments', $userenrolmentdata);
 217  
 218          // Create a student with an assignment grade.
 219          $student = self::getDataGenerator()->create_user();
 220          $assigngrade = new \stdClass();
 221          $assigngrade->assignment = $assign->id;
 222          $assigngrade->userid = $student->id;
 223          $assigngrade->timecreated = time();
 224          $assigngrade->timemodified = $assigngrade->timecreated;
 225          $assigngrade->grader = $USER->id;
 226          $assigngrade->grade = 50;
 227          $assigngrade->attemptnumber = 0;
 228          $gid = $DB->insert_record('assign_grades', $assigngrade);
 229  
 230          // Create a grading area.
 231          $gradingarea = array(
 232              'contextid' => $modulecontext->id,
 233              'component' => 'mod_assign',
 234              'areaname' => 'submissions',
 235              'activemethod' => 'rubric'
 236          );
 237          $areaid = $DB->insert_record('grading_areas', $gradingarea);
 238  
 239          // Create a rubric grading definition.
 240          $rubricdefinition = array (
 241              'areaid' => $areaid,
 242              'method' => 'rubric',
 243              'name' => 'test',
 244              'status' => 20,
 245              'copiedfromid' => 1,
 246              'timecreated' => 1,
 247              'usercreated' => $USER->id,
 248              'timemodified' => 1,
 249              'usermodified' => $USER->id,
 250              'timecopied' => 0
 251          );
 252          $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
 253  
 254          // Create a criterion with a level.
 255          $rubriccriteria = array (
 256              'definitionid' => $definitionid,
 257              'sortorder' => 1,
 258              'description' => 'Demonstrate an understanding of disease control',
 259              'descriptionformat' => 0
 260          );
 261          $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria);
 262          $rubriclevel = array (
 263              'criterionid' => $criterionid,
 264              'score' => 50,
 265              'definition' => 'pass',
 266              'definitionformat' => 0
 267          );
 268          $levelid = $DB->insert_record('gradingform_rubric_levels', $rubriclevel);
 269  
 270          // Create a grading instance.
 271          $instance = array (
 272              'definitionid' => $definitionid,
 273              'raterid' => $USER->id,
 274              'itemid' => $gid,
 275              'status' => 1,
 276              'feedbackformat' => 0,
 277              'timemodified' => 1
 278          );
 279          $instanceid = $DB->insert_record('grading_instances', $instance);
 280  
 281          // Create a filling.
 282          $filling = array (
 283              'instanceid' => $instanceid,
 284              'criterionid' => $criterionid,
 285              'levelid' => $levelid,
 286              'remark' => 'excellent work',
 287              'remarkformat' => 0
 288          );
 289          $DB->insert_record('gradingform_rubric_fillings', $filling);
 290  
 291          // Call the external function.
 292          $result = core_grading_external::get_gradingform_instances($definitionid, 0);
 293          $result = \external_api::clean_returnvalue(core_grading_external::get_gradingform_instances_returns(), $result);
 294  
 295          $this->assertEquals(1, count($result['instances']));
 296          $this->assertEquals($USER->id, $result['instances'][0]['raterid']);
 297          $this->assertEquals($gid, $result['instances'][0]['itemid']);
 298          $this->assertEquals(1, $result['instances'][0]['status']);
 299          $this->assertEquals(1, $result['instances'][0]['timemodified']);
 300          $this->assertEquals(1, count($result['instances'][0]['rubric']));
 301          $this->assertEquals(1, count($result['instances'][0]['rubric']['criteria']));
 302          $criteria = $result['instances'][0]['rubric']['criteria'];
 303          $this->assertEquals($criterionid, $criteria[0]['criterionid']);
 304          $this->assertEquals($levelid, $criteria[0]['levelid']);
 305          $this->assertEquals('excellent work', $criteria[0]['remark']);
 306      }
 307  
 308      /**
 309       *
 310       * Test save_definitions for rubric grading method
 311       */
 312      public function test_save_definitions_rubric() {
 313          global $DB, $CFG, $USER;
 314  
 315          $this->resetAfterTest(true);
 316          // Create a course and assignment.
 317          $course = self::getDataGenerator()->create_course();
 318          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 319          $params['course'] = $course->id;
 320          $instance = $generator->create_instance($params);
 321          $cm = get_coursemodule_from_instance('assign', $instance->id);
 322          $context = \context_module::instance($cm->id);
 323          $coursecontext = \context_course::instance($course->id);
 324  
 325          // Create the teacher.
 326          $teacher = self::getDataGenerator()->create_user();
 327          $USER->id = $teacher->id;
 328          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 329          $this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
 330          $this->getDataGenerator()->enrol_user($teacher->id,
 331                                                $course->id,
 332                                                $teacherrole->id);
 333  
 334          // The grading area to insert.
 335          $gradingarea = array(
 336              'cmid' => $cm->id,
 337              'contextid' => $context->id,
 338              'component' => 'mod_assign',
 339              'areaname'  => 'submissions',
 340              'activemethod' => 'rubric'
 341          );
 342  
 343          // The rubric definition to insert.
 344          $rubricdefinition = array(
 345              'method' => 'rubric',
 346              'name' => 'test',
 347              'description' => '',
 348              'status' => 20,
 349              'copiedfromid' => 1,
 350              'timecreated' => 1,
 351              'usercreated' => $teacher->id,
 352              'timemodified' => 1,
 353              'usermodified' => $teacher->id,
 354              'timecopied' => 0
 355          );
 356  
 357          // The criterion to insert.
 358          $rubriccriteria1 = array (
 359               'sortorder' => 1,
 360               'description' => 'Demonstrate an understanding of disease control',
 361               'descriptionformat' => 0
 362          );
 363  
 364          // 3 levels for the criterion.
 365          $rubriclevel1 = array (
 366              'score' => 50,
 367              'definition' => 'pass',
 368              'definitionformat' => 0
 369          );
 370          $rubriclevel2 = array (
 371              'score' => 100,
 372              'definition' => 'excellent',
 373              'definitionformat' => 0
 374          );
 375          $rubriclevel3 = array (
 376              'score' => 0,
 377              'definition' => 'fail',
 378              'definitionformat' => 0
 379          );
 380  
 381          $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3);
 382          $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
 383          $gradingarea['definitions'] = array($rubricdefinition);
 384  
 385          $results = core_grading_external::save_definitions(array($gradingarea));
 386  
 387          $area = $DB->get_record('grading_areas',
 388                                  array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
 389                                  '*', MUST_EXIST);
 390          $this->assertEquals($area->activemethod, 'rubric');
 391  
 392          $definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'rubric'), '*', MUST_EXIST);
 393          $this->assertEquals($rubricdefinition['name'], $definition->name);
 394  
 395          $criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
 396          $levels = $DB->get_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id));
 397          $validlevelcount = 0;
 398          $expectedvalue = true;
 399          foreach ($levels as $level) {
 400              if ($level->score == 0) {
 401                  $this->assertEquals('fail', $level->definition);
 402                  $validlevelcount++;
 403              } else if ($level->score == 50) {
 404                  $this->assertEquals('pass', $level->definition);
 405                  $validlevelcount++;
 406              } else if ($level->score == 100) {
 407                  $this->assertEquals('excellent', $level->definition);
 408                  $excellentlevelid = $level->id;
 409                  $validlevelcount++;
 410              } else {
 411                  $expectedvalue = false;
 412              }
 413          }
 414          $this->assertEquals(3, $validlevelcount);
 415          $this->assertTrue($expectedvalue, 'A level with an unexpected score was found');
 416  
 417          // Test add a new level and modify an existing.
 418          // Test add a new criteria and modify an existing.
 419          // Test modify a definition.
 420  
 421          // The rubric definition to update.
 422          $rubricdefinition = array(
 423              'id' => $definition->id,
 424              'method' => 'rubric',
 425              'name' => 'test changed',
 426              'description' => '',
 427              'status' => 20,
 428              'copiedfromid' => 1,
 429              'timecreated' => 1,
 430              'usercreated' => $teacher->id,
 431              'timemodified' => 1,
 432              'usermodified' => $teacher->id,
 433              'timecopied' => 0
 434          );
 435  
 436          // A criterion to update.
 437          $rubriccriteria1 = array (
 438               'id' => $criterion1->id,
 439               'sortorder' => 1,
 440               'description' => 'Demonstrate an understanding of rabies control',
 441               'descriptionformat' => 0
 442          );
 443  
 444          // A new criterion to add.
 445          $rubriccriteria2 = array (
 446               'sortorder' => 2,
 447               'description' => 'Demonstrate an understanding of anthrax control',
 448               'descriptionformat' => 0
 449          );
 450  
 451          // A level to update.
 452          $rubriclevel2 = array (
 453              'id' => $excellentlevelid,
 454              'score' => 75,
 455              'definition' => 'excellent',
 456              'definitionformat' => 0
 457          );
 458  
 459          // A level to insert.
 460          $rubriclevel4 = array (
 461              'score' => 100,
 462              'definition' => 'superb',
 463              'definitionformat' => 0
 464          );
 465  
 466          $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3, $rubriclevel4);
 467          $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1, $rubriccriteria2));
 468          $gradingarea['definitions'] = array($rubricdefinition);
 469  
 470          $results = core_grading_external::save_definitions(array($gradingarea));
 471  
 472          // Test definition name change.
 473          $definition = $DB->get_record('grading_definitions', array('id' => $definition->id), '*', MUST_EXIST);
 474          $this->assertEquals('test changed', $definition->name);
 475  
 476          // Test criteria description change.
 477          $modifiedcriteria = $DB->get_record('gradingform_rubric_criteria', array('id' => $criterion1->id), '*', MUST_EXIST);
 478          $this->assertEquals('Demonstrate an understanding of rabies control', $modifiedcriteria->description);
 479  
 480          // Test new criteria added.
 481          $newcriteria = $DB->get_record('gradingform_rubric_criteria',
 482                                         array('definitionid' => $definition->id, 'sortorder' => 2), '*', MUST_EXIST);
 483          $this->assertEquals('Demonstrate an understanding of anthrax control', $newcriteria->description);
 484  
 485          // Test excellent level score change from 100 to 75.
 486          $modifiedlevel = $DB->get_record('gradingform_rubric_levels', array('id' => $excellentlevelid), '*', MUST_EXIST);
 487          $this->assertEquals(75, $modifiedlevel->score);
 488  
 489          // Test new superb level added.
 490          $newlevel = $DB->get_record('gradingform_rubric_levels',
 491                                         array('criterionid' => $criterion1->id, 'score' => 100), '*', MUST_EXIST);
 492          $this->assertEquals('superb', $newlevel->definition);
 493  
 494          // Test remove a level
 495          // Test remove a criterion
 496          // The rubric definition with the removed criterion and levels.
 497          $rubricdefinition = array(
 498              'id' => $definition->id,
 499              'method' => 'rubric',
 500              'name' => 'test changed',
 501              'description' => '',
 502              'status' => 20,
 503              'copiedfromid' => 1,
 504              'timecreated' => 1,
 505              'usercreated' => $teacher->id,
 506              'timemodified' => 1,
 507              'usermodified' => $teacher->id,
 508              'timecopied' => 0
 509          );
 510  
 511          $rubriccriteria1 = array (
 512               'id' => $criterion1->id,
 513               'sortorder' => 1,
 514               'description' => 'Demonstrate an understanding of rabies control',
 515               'descriptionformat' => 0
 516          );
 517  
 518          $rubriclevel1 = array (
 519              'score' => 0,
 520              'definition' => 'fail',
 521              'definitionformat' => 0
 522          );
 523          $rubriclevel2 = array (
 524              'score' => 100,
 525              'definition' => 'pass',
 526              'definitionformat' => 0
 527          );
 528  
 529          $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2);
 530          $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
 531          $gradingarea['definitions'] = array($rubricdefinition);
 532  
 533          $results = core_grading_external::save_definitions(array($gradingarea));
 534  
 535          // Only 1 criterion should now exist.
 536          $this->assertEquals(1, $DB->count_records('gradingform_rubric_criteria', array('definitionid' => $definition->id)));
 537          $criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
 538          $this->assertEquals('Demonstrate an understanding of rabies control', $criterion1->description);
 539          // This criterion should only have 2 levels.
 540          $this->assertEquals(2, $DB->count_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id)));
 541  
 542          $gradingarea['activemethod'] = 'invalid';
 543          $this->expectException('moodle_exception');
 544          $results = core_grading_external::save_definitions(array($gradingarea));
 545      }
 546  
 547      /**
 548       *
 549       * Tests save_definitions for the marking guide grading method
 550       */
 551      public function test_save_definitions_marking_guide() {
 552          global $DB, $CFG, $USER;
 553  
 554          $this->resetAfterTest(true);
 555          // Create a course and assignment.
 556          $course = self::getDataGenerator()->create_course();
 557          $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 558          $params['course'] = $course->id;
 559          $instance = $generator->create_instance($params);
 560          $cm = get_coursemodule_from_instance('assign', $instance->id);
 561          $context = \context_module::instance($cm->id);
 562          $coursecontext = \context_course::instance($course->id);
 563  
 564          // Create the teacher.
 565          $teacher = self::getDataGenerator()->create_user();
 566          $USER->id = $teacher->id;
 567          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 568          $this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
 569          $this->getDataGenerator()->enrol_user($teacher->id,
 570                                                $course->id,
 571                                                $teacherrole->id);
 572  
 573          // Test insert a grading area with guide definition, criteria and comments.
 574          $gradingarea = array(
 575              'cmid' => $cm->id,
 576              'contextid' => $context->id,
 577              'component' => 'mod_assign',
 578              'areaname'  => 'submissions',
 579              'activemethod' => 'guide'
 580          );
 581  
 582          $guidedefinition = array(
 583              'method' => 'guide',
 584              'name' => 'test',
 585              'description' => '',
 586              'status' => 20,
 587              'copiedfromid' => 1,
 588              'timecreated' => 1,
 589              'usercreated' => $teacher->id,
 590              'timemodified' => 1,
 591              'usermodified' => $teacher->id,
 592              'timecopied' => 0
 593          );
 594  
 595          $guidecomment = array(
 596               'sortorder' => 1,
 597               'description' => 'Students need to show that they understand the control of zoonoses',
 598               'descriptionformat' => 0
 599          );
 600          $guidecriteria1 = array (
 601               'sortorder' => 1,
 602               'shortname' => 'Rabies Control',
 603               'description' => 'Understand rabies control techniques',
 604               'descriptionformat' => 0,
 605               'descriptionmarkers' => 'Student must demonstrate that they understand rabies control',
 606               'descriptionmarkersformat' => 0,
 607               'maxscore' => 50
 608          );
 609          $guidecriteria2 = array (
 610               'sortorder' => 2,
 611               'shortname' => 'Anthrax Control',
 612               'description' => 'Understand anthrax control',
 613               'descriptionformat' => 0,
 614               'descriptionmarkers' => 'Student must demonstrate that they understand anthrax control',
 615               'descriptionmarkersformat' => 0,
 616               'maxscore' => 50
 617          );
 618  
 619          $guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1, $guidecriteria2),
 620                                            'guide_comments' => array($guidecomment));
 621          $gradingarea['definitions'] = array($guidedefinition);
 622  
 623          $results = core_grading_external::save_definitions(array($gradingarea));
 624          $area = $DB->get_record('grading_areas',
 625                                  array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
 626                                  '*', MUST_EXIST);
 627          $this->assertEquals($area->activemethod, 'guide');
 628  
 629          $definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'guide'), '*', MUST_EXIST);
 630          $this->assertEquals($guidedefinition['name'], $definition->name);
 631          $this->assertEquals(2, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
 632          $this->assertEquals(1, $DB->count_records('gradingform_guide_comments', array('definitionid' => $definition->id)));
 633  
 634          // Test removal of a criteria.
 635          $guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1),
 636                                            'guide_comments' => array($guidecomment));
 637          $gradingarea['definitions'] = array($guidedefinition);
 638          $results = core_grading_external::save_definitions(array($gradingarea));
 639          $this->assertEquals(1, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
 640  
 641          // Test an invalid method in the definition.
 642          $guidedefinition['method'] = 'invalid';
 643          $gradingarea['definitions'] = array($guidedefinition);
 644          $this->expectException('invalid_parameter_exception');
 645          $results = core_grading_external::save_definitions(array($gradingarea));
 646      }
 647  }