Differences Between: [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 * Unit tests for core_grades\component_gradeitems; 19 * 20 * @package gradingform_rubric 21 * @category test 22 * @copyright 2019 Mathew May <mathew.solutions> 23 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License 24 */ 25 26 declare(strict_types = 1); 27 28 namespace gradingform_rubric\grades\grader\gradingpanel\external; 29 30 use advanced_testcase; 31 use coding_exception; 32 use core_grades\component_gradeitem; 33 use core_grades\component_gradeitems; 34 use external_api; 35 use mod_forum\local\entities\forum as forum_entity; 36 use moodle_exception; 37 38 /** 39 * Unit tests for core_grades\component_gradeitems; 40 * 41 * @package gradingform_rubric 42 * @category test 43 * @copyright 2019 Mathew May <mathew.solutions> 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 class fetch_test extends advanced_testcase { 47 48 public static function setupBeforeClass(): void { 49 global $CFG; 50 require_once("{$CFG->libdir}/externallib.php"); 51 } 52 53 /** 54 * Ensure that an execute with an invalid component is rejected. 55 */ 56 public function test_execute_invalid_component(): void { 57 $this->resetAfterTest(); 58 $user = $this->getDataGenerator()->create_user(); 59 $this->setUser($user); 60 61 $this->expectException(coding_exception::class); 62 $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_invalid' component"); 63 fetch::execute('mod_invalid', 1, 'foo', 2); 64 } 65 66 /** 67 * Ensure that an execute with an invalid itemname on a valid component is rejected. 68 */ 69 public function test_execute_invalid_itemname(): void { 70 $this->resetAfterTest(); 71 $user = $this->getDataGenerator()->create_user(); 72 $this->setUser($user); 73 74 $this->expectException(coding_exception::class); 75 $this->expectExceptionMessage("The 'foo' item is not valid for the 'mod_forum' component"); 76 fetch::execute('mod_forum', 1, 'foo', 2); 77 } 78 79 /** 80 * Ensure that an execute against a different grading method is rejected. 81 */ 82 public function test_execute_incorrect_type(): void { 83 $this->resetAfterTest(); 84 85 $forum = $this->get_forum_instance([ 86 // Negative numbers mean a scale. 87 'grade_forum' => 5, 88 ]); 89 $course = $forum->get_course_record(); 90 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 91 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 92 $this->setUser($teacher); 93 94 $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum'); 95 96 $this->expectException(moodle_exception::class); 97 $this->expectExceptionMessage("not configured for advanced grading with a rubric"); 98 fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id); 99 } 100 101 /** 102 * Ensure that an execute against the correct grading method returns the current state of the user. 103 */ 104 public function test_execute_fetch_empty(): void { 105 $this->resetAfterTest(); 106 107 [ 108 'forum' => $forum, 109 'controller' => $controller, 110 'definition' => $definition, 111 'student' => $student, 112 'teacher' => $teacher, 113 ] = $this->get_test_data(); 114 115 $this->setUser($teacher); 116 117 $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum'); 118 119 $result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id); 120 $result = external_api::clean_returnvalue(fetch::execute_returns(), $result); 121 122 $this->assertIsArray($result); 123 $this->assertArrayHasKey('templatename', $result); 124 125 $this->assertEquals('gradingform_rubric/grades/grader/gradingpanel', $result['templatename']); 126 127 $this->assertArrayHasKey('warnings', $result); 128 $this->assertIsArray($result['warnings']); 129 $this->assertEmpty($result['warnings']); 130 131 // Test the grade array items. 132 $this->assertArrayHasKey('grade', $result); 133 $this->assertIsArray($result['grade']); 134 $this->assertIsInt($result['grade']['timecreated']); 135 136 $this->assertArrayHasKey('timemodified', $result['grade']); 137 $this->assertIsInt($result['grade']['timemodified']); 138 139 $this->assertArrayHasKey('usergrade', $result['grade']); 140 $this->assertEquals('- / 100.00', $result['grade']['usergrade']); 141 142 $this->assertArrayHasKey('maxgrade', $result['grade']); 143 $this->assertIsInt($result['grade']['maxgrade']); 144 $this->assertEquals(100, $result['grade']['maxgrade']); 145 146 $this->assertArrayHasKey('gradedby', $result['grade']); 147 $this->assertEquals(null, $result['grade']['gradedby']); 148 149 $this->assertArrayHasKey('criteria', $result['grade']); 150 $criteria = $result['grade']['criteria']; 151 $this->assertCount(count($definition->rubric_criteria), $criteria); 152 foreach ($criteria as $criterion) { 153 $this->assertArrayHasKey('id', $criterion); 154 $criterionid = $criterion['id']; 155 $sourcecriterion = $definition->rubric_criteria[$criterionid]; 156 157 $this->assertArrayHasKey('description', $criterion); 158 $this->assertEquals($sourcecriterion['description'], $criterion['description']); 159 160 $this->assertArrayHasKey('levels', $criterion); 161 162 $levels = $criterion['levels']; 163 foreach ($levels as $level) { 164 $levelid = $level['id']; 165 if (!isset($levelid)) { 166 continue; 167 } 168 $sourcelevel = $sourcecriterion['levels'][$levelid]; 169 170 $this->assertArrayHasKey('criterionid', $level); 171 $this->assertEquals($criterionid, $level['criterionid']); 172 173 $this->assertArrayHasKey('checked', $level); 174 175 $this->assertArrayHasKey('definition', $level); 176 $this->assertEquals($sourcelevel['definition'], $level['definition']); 177 178 $this->assertArrayHasKey('score', $level); 179 $this->assertEquals($sourcelevel['score'], $level['score']); 180 } 181 } 182 } 183 184 /** 185 * Ensure that an execute against the correct grading method returns the current state of the user. 186 */ 187 public function test_execute_fetch_graded(): void { 188 $this->resetAfterTest(); 189 190 [ 191 'forum' => $forum, 192 'controller' => $controller, 193 'definition' => $definition, 194 'student' => $student, 195 'teacher' => $teacher, 196 ] = $this->get_test_data(); 197 198 $this->execute_and_assert_fetch($forum, $controller, $definition, $teacher, $teacher, $student); 199 } 200 201 /** 202 * Class mates should not get other's grades. 203 */ 204 public function test_execute_fetch_does_not_return_data_to_other_students(): void { 205 $this->resetAfterTest(); 206 207 [ 208 'forum' => $forum, 209 'controller' => $controller, 210 'definition' => $definition, 211 'student' => $student, 212 'teacher' => $teacher, 213 'course' => $course, 214 ] = $this->get_test_data(); 215 216 $evilstudent = $this->getDataGenerator()->create_and_enrol($course, 'student'); 217 218 $this->expectException(\required_capability_exception::class); 219 $this->execute_and_assert_fetch($forum, $controller, $definition, $evilstudent, $teacher, $student); 220 } 221 222 /** 223 * Grades can be returned to graded user. 224 */ 225 public function test_execute_fetch_return_data_to_graded_user(): void { 226 $this->resetAfterTest(); 227 228 [ 229 'forum' => $forum, 230 'controller' => $controller, 231 'definition' => $definition, 232 'student' => $student, 233 'teacher' => $teacher, 234 ] = $this->get_test_data(); 235 236 $this->execute_and_assert_fetch($forum, $controller, $definition, $student, $teacher, $student); 237 } 238 239 /** 240 * Executes and performs all the assertions of the fetch method with the given parameters. 241 */ 242 private function execute_and_assert_fetch ($forum, $controller, $definition, $fetcheruser, $grader, $gradeduser) { 243 $generator = \testing_util::get_data_generator(); 244 $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric'); 245 246 $this->setUser($grader); 247 248 $gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum'); 249 $grade = $gradeitem->get_grade_for_user($gradeduser, $grader); 250 $instance = $gradeitem->get_advanced_grading_instance($grader, $grade); 251 252 $submissiondata = $rubricgenerator->get_test_form_data($controller, (int) $gradeduser->id, 253 0, 'Too many mistakes. Please try again.', 254 2, 'Great number of pictures. Well done.' 255 ); 256 257 $gradeitem->store_grade_from_formdata($gradeduser, $grader, (object) [ 258 'instanceid' => $instance->get_id(), 259 'advancedgrading' => $submissiondata, 260 ]); 261 262 $this->setUser($fetcheruser); 263 264 $result = fetch::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $gradeduser->id); 265 $result = external_api::clean_returnvalue(fetch::execute_returns(), $result); 266 267 $this->assertIsArray($result); 268 $this->assertArrayHasKey('templatename', $result); 269 270 $this->assertEquals('gradingform_rubric/grades/grader/gradingpanel', $result['templatename']); 271 272 $this->assertArrayHasKey('warnings', $result); 273 $this->assertIsArray($result['warnings']); 274 $this->assertEmpty($result['warnings']); 275 276 // Test the grade array items. 277 $this->assertArrayHasKey('grade', $result); 278 $this->assertIsArray($result['grade']); 279 $this->assertIsInt($result['grade']['timecreated']); 280 281 $this->assertArrayHasKey('timemodified', $result['grade']); 282 $this->assertIsInt($result['grade']['timemodified']); 283 284 $this->assertArrayHasKey('usergrade', $result['grade']); 285 $this->assertEquals('50.00 / 100.00', $result['grade']['usergrade']); 286 287 $this->assertArrayHasKey('maxgrade', $result['grade']); 288 $this->assertIsInt($result['grade']['maxgrade']); 289 $this->assertEquals(100, $result['grade']['maxgrade']); 290 291 $this->assertArrayHasKey('gradedby', $result['grade']); 292 $this->assertEquals(fullname($grader), $result['grade']['gradedby']); 293 294 $this->assertArrayHasKey('criteria', $result['grade']); 295 $criteria = $result['grade']['criteria']; 296 $this->assertCount(count($definition->rubric_criteria), $criteria); 297 foreach ($criteria as $criterion) { 298 $this->assertArrayHasKey('id', $criterion); 299 $criterionid = $criterion['id']; 300 $sourcecriterion = $definition->rubric_criteria[$criterionid]; 301 302 $this->assertArrayHasKey('description', $criterion); 303 $this->assertEquals($sourcecriterion['description'], $criterion['description']); 304 305 $this->assertArrayHasKey('remark', $criterion); 306 307 $this->assertArrayHasKey('levels', $criterion); 308 309 $levels = $criterion['levels']; 310 foreach ($levels as $level) { 311 $levelid = $level['id']; 312 if (!isset($levelid)) { 313 continue; 314 } 315 $sourcelevel = $sourcecriterion['levels'][$levelid]; 316 317 $this->assertArrayHasKey('criterionid', $level); 318 $this->assertEquals($criterionid, $level['criterionid']); 319 320 $this->assertArrayHasKey('checked', $level); 321 322 $this->assertArrayHasKey('definition', $level); 323 $this->assertEquals($sourcelevel['definition'], $level['definition']); 324 325 $this->assertArrayHasKey('score', $level); 326 $this->assertEquals($sourcelevel['score'], $level['score']); 327 } 328 329 } 330 331 $this->assertEquals(1, $criteria[0]['levels'][1]['checked']); 332 $this->assertEquals('Too many mistakes. Please try again.', $criteria[0]['remark']); 333 $this->assertEquals(1, $criteria[1]['levels'][3]['checked']); 334 $this->assertEquals('Great number of pictures. Well done.', $criteria[1]['remark']); 335 } 336 337 /** 338 * Get a forum instance. 339 * 340 * @param array $config 341 * @return forum_entity 342 */ 343 protected function get_forum_instance(array $config = []): forum_entity { 344 $this->resetAfterTest(); 345 346 $datagenerator = $this->getDataGenerator(); 347 $course = $datagenerator->create_course(); 348 $forum = $datagenerator->create_module('forum', array_merge($config, ['course' => $course->id, 'grade_forum' => 100])); 349 350 $vaultfactory = \mod_forum\local\container::get_vault_factory(); 351 $vault = $vaultfactory->get_forum_vault(); 352 353 return $vault->get_from_id((int) $forum->id); 354 } 355 356 /** 357 * Get test data for forums graded using a rubric. 358 * 359 * @return array 360 */ 361 protected function get_test_data(): array { 362 global $DB; 363 364 $this->resetAfterTest(); 365 366 $generator = \testing_util::get_data_generator(); 367 $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric'); 368 369 $forum = $this->get_forum_instance(); 370 $course = $forum->get_course_record(); 371 $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher'); 372 $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); 373 374 $this->setUser($teacher); 375 376 $controller = $rubricgenerator->get_test_rubric($forum->get_context(), 'forum', 'forum'); 377 $definition = $controller->get_definition(); 378 379 // In the situation of mod_forum this would be the id from forum_grades. 380 $itemid = 1; 381 $instance = $controller->create_instance($student->id, $itemid); 382 383 $data = $this->get_test_form_data( 384 $controller, 385 $itemid, 386 1, 'This user made several mistakes.', 387 0, 'Please add more pictures.' 388 ); 389 390 // Update this instance with data. 391 $instance->update($data); 392 393 return [ 394 'forum' => $forum, 395 'controller' => $controller, 396 'definition' => $definition, 397 'student' => $student, 398 'teacher' => $teacher, 399 'course' => $course, 400 ]; 401 } 402 /** 403 * Fetch a set of sample data. 404 * 405 * @param \gradingform_rubric_controller $controller 406 * @param int $itemid 407 * @param float $spellingscore 408 * @param string $spellingremark 409 * @param float $picturescore 410 * @param string $pictureremark 411 * @return array 412 */ 413 protected function get_test_form_data( 414 \gradingform_rubric_controller $controller, 415 int $itemid, 416 float $spellingscore, 417 string $spellingremark, 418 float $picturescore, 419 string $pictureremark 420 ): array { 421 $generator = \testing_util::get_data_generator(); 422 $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric'); 423 424 return $rubricgenerator->get_test_form_data( 425 $controller, 426 $itemid, 427 $spellingscore, 428 $spellingremark, 429 $picturescore, 430 $pictureremark 431 ); 432 } 433 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body