PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/grade/tests/grade_grade_test.php

http://github.com/moodle/moodle
PHP | 509 lines | 314 code | 100 blank | 95 comment | 1 complexity | ceae3d493237633ade197c81c2129b28 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  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. * @package core_grades
  18. * @category phpunit
  19. * @copyright nicolas@moodle.com
  20. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  21. */
  22. defined('MOODLE_INTERNAL') || die();
  23. require_once(__DIR__.'/fixtures/lib.php');
  24. class core_grade_grade_testcase extends grade_base_testcase {
  25. public function test_grade_grade() {
  26. $this->sub_test_grade_grade_construct();
  27. $this->sub_test_grade_grade_insert();
  28. $this->sub_test_grade_grade_update();
  29. $this->sub_test_grade_grade_fetch();
  30. $this->sub_test_grade_grade_fetch_all();
  31. $this->sub_test_grade_grade_load_grade_item();
  32. $this->sub_test_grade_grade_standardise_score();
  33. $this->sub_test_grade_grade_is_locked();
  34. $this->sub_test_grade_grade_set_hidden();
  35. $this->sub_test_grade_grade_is_hidden();
  36. $this->sub_test_grade_grade_deleted();
  37. }
  38. protected function sub_test_grade_grade_construct() {
  39. $params = new stdClass();
  40. $params->itemid = $this->grade_items[0]->id;
  41. $params->userid = 1;
  42. $params->rawgrade = 88;
  43. $params->rawgrademax = 110;
  44. $params->rawgrademin = 18;
  45. $grade_grade = new grade_grade($params, false);
  46. $this->assertEquals($params->itemid, $grade_grade->itemid);
  47. $this->assertEquals($params->rawgrade, $grade_grade->rawgrade);
  48. }
  49. protected function sub_test_grade_grade_insert() {
  50. $grade_grade = new grade_grade();
  51. $this->assertTrue(method_exists($grade_grade, 'insert'));
  52. $grade_grade->itemid = $this->grade_items[0]->id;
  53. $grade_grade->userid = 10;
  54. $grade_grade->rawgrade = 88;
  55. $grade_grade->rawgrademax = 110;
  56. $grade_grade->rawgrademin = 18;
  57. // Check the grade_item's needsupdate variable first.
  58. $grade_grade->load_grade_item();
  59. $this->assertEmpty($grade_grade->grade_item->needsupdate);
  60. $grade_grade->insert();
  61. $last_grade_grade = end($this->grade_grades);
  62. $this->assertEquals($grade_grade->id, $last_grade_grade->id + 1);
  63. // Timecreated will only be set if the grade was submitted by an activity module.
  64. $this->assertTrue(empty($grade_grade->timecreated));
  65. // Timemodified will only be set if the grade was submitted by an activity module.
  66. $this->assertTrue(empty($grade_grade->timemodified));
  67. // Keep our collection the same as is in the database.
  68. $this->grade_grades[] = $grade_grade;
  69. }
  70. protected function sub_test_grade_grade_update() {
  71. $grade_grade = new grade_grade($this->grade_grades[0], false);
  72. $this->assertTrue(method_exists($grade_grade, 'update'));
  73. }
  74. protected function sub_test_grade_grade_fetch() {
  75. $grade_grade = new grade_grade();
  76. $this->assertTrue(method_exists($grade_grade, 'fetch'));
  77. $grades = grade_grade::fetch(array('id'=>$this->grade_grades[0]->id));
  78. $this->assertEquals($this->grade_grades[0]->id, $grades->id);
  79. $this->assertEquals($this->grade_grades[0]->rawgrade, $grades->rawgrade);
  80. }
  81. protected function sub_test_grade_grade_fetch_all() {
  82. $grade_grade = new grade_grade();
  83. $this->assertTrue(method_exists($grade_grade, 'fetch_all'));
  84. $grades = grade_grade::fetch_all(array());
  85. $this->assertEquals(count($this->grade_grades), count($grades));
  86. }
  87. protected function sub_test_grade_grade_load_grade_item() {
  88. $grade_grade = new grade_grade($this->grade_grades[0], false);
  89. $this->assertTrue(method_exists($grade_grade, 'load_grade_item'));
  90. $this->assertNull($grade_grade->grade_item);
  91. $this->assertNotEmpty($grade_grade->itemid);
  92. $this->assertNotNull($grade_grade->load_grade_item());
  93. $this->assertNotNull($grade_grade->grade_item);
  94. $this->assertEquals($this->grade_items[0]->id, $grade_grade->grade_item->id);
  95. }
  96. protected function sub_test_grade_grade_standardise_score() {
  97. $this->assertEquals(4, round(grade_grade::standardise_score(6, 0, 7, 0, 5)));
  98. $this->assertEquals(40, grade_grade::standardise_score(50, 30, 80, 0, 100));
  99. }
  100. /*
  101. * Disabling this test: the set_locked() arguments have been modified, rendering these tests useless until they are re-written
  102. protected function test_grade_grade_set_locked() {
  103. $grade_item = new grade_item($this->grade_items[0]);
  104. $grade = new grade_grade($grade_item->get_final(1));
  105. $this->assertTrue(method_exists($grade, 'set_locked'));
  106. $this->assertTrue(empty($grade_item->locked));
  107. $this->assertTrue(empty($grade->locked));
  108. $this->assertTrue($grade->set_locked(true));
  109. $this->assertFalse(empty($grade->locked));
  110. $this->assertTrue($grade->set_locked(false));
  111. $this->assertTrue(empty($grade->locked));
  112. $this->assertTrue($grade_item->set_locked(true, true));
  113. $grade = new grade_grade($grade_item->get_final(1));
  114. $this->assertFalse(empty($grade->locked));
  115. $this->assertFalse($grade->set_locked(true, false));
  116. $this->assertTrue($grade_item->set_locked(true, false));
  117. $grade = new grade_grade($grade_item->get_final(1));
  118. $this->assertTrue($grade->set_locked(true, false));
  119. }
  120. */
  121. protected function sub_test_grade_grade_is_locked() {
  122. $grade = new grade_grade($this->grade_grades[0], false);
  123. $this->assertTrue(method_exists($grade, 'is_locked'));
  124. $this->assertFalse($grade->is_locked());
  125. $grade->locked = time();
  126. $this->assertTrue($grade->is_locked());
  127. }
  128. protected function sub_test_grade_grade_set_hidden() {
  129. $grade = new grade_grade($this->grade_grades[0], false);
  130. $grade_item = new grade_item($this->grade_items[0], false);
  131. $this->assertTrue(method_exists($grade, 'set_hidden'));
  132. $this->assertEquals(0, $grade_item->hidden);
  133. $this->assertEquals(0, $grade->hidden);
  134. $grade->set_hidden(0);
  135. $this->assertEquals(0, $grade->hidden);
  136. $grade->set_hidden(1);
  137. $this->assertEquals(1, $grade->hidden);
  138. $grade->set_hidden(0);
  139. $this->assertEquals(0, $grade->hidden);
  140. }
  141. protected function sub_test_grade_grade_is_hidden() {
  142. $grade = new grade_grade($this->grade_grades[0], false);
  143. $this->assertTrue(method_exists($grade, 'is_hidden'));
  144. $this->assertFalse($grade->is_hidden());
  145. $grade->hidden = 1;
  146. $this->assertTrue($grade->is_hidden());
  147. $grade->hidden = time()-666;
  148. $this->assertFalse($grade->is_hidden());
  149. $grade->hidden = time()+666;
  150. $this->assertTrue($grade->is_hidden());
  151. }
  152. public function test_flatten_dependencies() {
  153. // First test a simple normal case.
  154. $a = array(1 => array(2, 3), 2 => array(), 3 => array(4), 4 => array());
  155. $b = array();
  156. $expecteda = array(1 => array(2, 3, 4), 2 => array(), 3 => array(4), 4 => array());
  157. $expectedb = array(1 => 1);
  158. test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
  159. $this->assertSame($expecteda, $a);
  160. $this->assertSame($expectedb, $b);
  161. // Edge case - empty arrays.
  162. $a = $b = $expecteda = $expectedb = array();
  163. test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
  164. $this->assertSame($expecteda, $a);
  165. $this->assertSame($expectedb, $b);
  166. // Circular dependency.
  167. $a = array(1 => array(2), 2 => array(3), 3 => array(1));
  168. $b = array();
  169. $expecteda = array(1 => array(1, 2, 3), 2 => array(1, 2, 3), 3 => array(1, 2, 3));
  170. test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
  171. $this->assertSame($expecteda, $a);
  172. // Note - we don't test the depth when we got circular dependencies - the main thing we wanted to test was that there was
  173. // no ka-boom. The result would be hard to understand and doesn't matter.
  174. // Circular dependency 2.
  175. $a = array(1 => array(2), 2 => array(3), 3 => array(4), 4 => array(2, 1));
  176. $b = array();
  177. $expecteda = array(1 => array(1, 2, 3, 4), 2 => array(1, 2, 3, 4), 3 => array(1, 2, 3, 4), 4 => array(1, 2, 3, 4));
  178. test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
  179. $this->assertSame($expecteda, $a);
  180. }
  181. public function test_grade_grade_min_max() {
  182. global $CFG;
  183. $initialminmaxtouse = $CFG->grade_minmaxtouse;
  184. $this->setAdminUser();
  185. $course = $this->getDataGenerator()->create_course();
  186. $user = $this->getDataGenerator()->create_user();
  187. $assignrecord = $this->getDataGenerator()->create_module('assign', array('course' => $course, 'grade' => 100));
  188. $cm = get_coursemodule_from_instance('assign', $assignrecord->id);
  189. $assigncontext = context_module::instance($cm->id);
  190. $assign = new assign($assigncontext, $cm, $course);
  191. // Fetch the assignment item.
  192. $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $assignrecord->id,
  193. 'courseid' => $course->id, 'itemnumber' => 0);
  194. $gi = grade_item::fetch($giparams);
  195. $this->assertEquals(0, $gi->grademin);
  196. $this->assertEquals(100, $gi->grademax);
  197. // Give a grade to the student.
  198. $usergrade = $assign->get_user_grade($user->id, true);
  199. $usergrade->grade = 10;
  200. $assign->update_grade($usergrade);
  201. // Check the grade stored in gradebook.
  202. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  203. $this->assertEquals(10, $gg->rawgrade);
  204. $this->assertEquals(0, $gg->get_grade_min());
  205. $this->assertEquals(100, $gg->get_grade_max());
  206. // Change the min/max grade of the item.
  207. $gi->grademax = 50;
  208. $gi->grademin = 2;
  209. $gi->update();
  210. // Fetch the updated item.
  211. $gi = grade_item::fetch($giparams);
  212. // Now check the grade grade min/max with system setting.
  213. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  214. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
  215. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  216. $this->assertEquals(2, $gg->get_grade_min());
  217. $this->assertEquals(50, $gg->get_grade_max());
  218. // Now with other system setting.
  219. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  220. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
  221. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  222. $this->assertEquals(0, $gg->get_grade_min());
  223. $this->assertEquals(100, $gg->get_grade_max());
  224. // Now with overriden setting in course.
  225. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  226. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
  227. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  228. $this->assertEquals(0, $gg->get_grade_min());
  229. $this->assertEquals(100, $gg->get_grade_max());
  230. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  231. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
  232. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  233. $this->assertEquals(2, $gg->get_grade_min());
  234. $this->assertEquals(50, $gg->get_grade_max());
  235. $CFG->grade_minmaxtouse = $initialminmaxtouse;
  236. }
  237. public function test_grade_grade_min_max_with_course_item() {
  238. global $CFG, $DB;
  239. $initialminmaxtouse = $CFG->grade_minmaxtouse;
  240. $this->setAdminUser();
  241. $course = $this->getDataGenerator()->create_course();
  242. $user = $this->getDataGenerator()->create_user();
  243. $gi = grade_item::fetch_course_item($course->id);
  244. // Fetch the category item.
  245. $this->assertEquals(0, $gi->grademin);
  246. $this->assertEquals(100, $gi->grademax);
  247. // Give a grade to the student.
  248. $gi->update_final_grade($user->id, 10);
  249. // Check the grade min/max stored in gradebook.
  250. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  251. $this->assertEquals(0, $gg->get_grade_min());
  252. $this->assertEquals(100, $gg->get_grade_max());
  253. // Change the min/max grade of the item.
  254. $gi->grademin = 2;
  255. $gi->grademax = 50;
  256. $gi->update();
  257. // Fetch the updated item.
  258. $gi = grade_item::fetch_course_item($course->id);
  259. // Now check the grade grade min/max with system setting.
  260. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  261. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
  262. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  263. $this->assertEquals(0, $gg->get_grade_min());
  264. $this->assertEquals(100, $gg->get_grade_max());
  265. // Now with other system setting.
  266. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  267. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
  268. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  269. $this->assertEquals(0, $gg->get_grade_min());
  270. $this->assertEquals(100, $gg->get_grade_max());
  271. // Now with overriden setting in course.
  272. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  273. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
  274. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  275. $this->assertEquals(0, $gg->get_grade_min());
  276. $this->assertEquals(100, $gg->get_grade_max());
  277. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  278. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
  279. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  280. $this->assertEquals(0, $gg->get_grade_min());
  281. $this->assertEquals(100, $gg->get_grade_max());
  282. $CFG->grade_minmaxtouse = $initialminmaxtouse;
  283. }
  284. public function test_grade_grade_min_max_with_category_item() {
  285. global $CFG, $DB;
  286. $initialminmaxtouse = $CFG->grade_minmaxtouse;
  287. $this->setAdminUser();
  288. $course = $this->getDataGenerator()->create_course();
  289. $user = $this->getDataGenerator()->create_user();
  290. $coursegi = grade_item::fetch_course_item($course->id);
  291. // Create a category item.
  292. $gc = new grade_category(array('courseid' => $course->id, 'fullname' => 'test'), false);
  293. $gc->insert();
  294. $gi = $gc->get_grade_item();
  295. $gi->grademax = 100;
  296. $gi->grademin = 0;
  297. $gi->update();
  298. // Fetch the category item.
  299. $giparams = array('itemtype' => 'category', 'iteminstance' => $gc->id);
  300. $gi = grade_item::fetch($giparams);
  301. $this->assertEquals(0, $gi->grademin);
  302. $this->assertEquals(100, $gi->grademax);
  303. // Give a grade to the student.
  304. $gi->update_final_grade($user->id, 10);
  305. // Check the grade min/max stored in gradebook.
  306. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  307. $this->assertEquals(0, $gg->get_grade_min());
  308. $this->assertEquals(100, $gg->get_grade_max());
  309. // Change the min/max grade of the item.
  310. $gi->grademin = 2;
  311. $gi->grademax = 50;
  312. $gi->update();
  313. // Fetch the updated item.
  314. $gi = grade_item::fetch($giparams);
  315. // Now check the grade grade min/max with system setting.
  316. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  317. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
  318. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  319. $this->assertEquals(0, $gg->get_grade_min());
  320. $this->assertEquals(100, $gg->get_grade_max());
  321. // Now with other system setting.
  322. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  323. grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
  324. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  325. $this->assertEquals(0, $gg->get_grade_min());
  326. $this->assertEquals(100, $gg->get_grade_max());
  327. // Now with overriden setting in course.
  328. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
  329. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
  330. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  331. $this->assertEquals(0, $gg->get_grade_min());
  332. $this->assertEquals(100, $gg->get_grade_max());
  333. $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
  334. grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
  335. $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
  336. $this->assertEquals(0, $gg->get_grade_min());
  337. $this->assertEquals(100, $gg->get_grade_max());
  338. $CFG->grade_minmaxtouse = $initialminmaxtouse;
  339. }
  340. /**
  341. * Tests when a grade_grade has been deleted.
  342. */
  343. public function sub_test_grade_grade_deleted() {
  344. $dg = $this->getDataGenerator();
  345. // Create the data we need for the tests.
  346. $fs = new file_storage();
  347. $u1 = $dg->create_user();
  348. $c1 = $dg->create_course();
  349. $a1 = $dg->create_module('assign', ['course' => $c1->id]);
  350. $a1context = context_module::instance($a1->cmid);
  351. $gi = new grade_item($dg->create_grade_item(
  352. [
  353. 'courseid' => $c1->id,
  354. 'itemtype' => 'mod',
  355. 'itemmodule' => 'assign',
  356. 'iteminstance' => $a1->id
  357. ]
  358. ), false);
  359. // Add feedback files to copy as our update.
  360. $this->add_feedback_file_to_copy();
  361. $grades['feedback'] = 'Nice feedback!';
  362. $grades['feedbackformat'] = FORMAT_MOODLE;
  363. $grades['feedbackfiles'] = [
  364. 'contextid' => 1,
  365. 'component' => 'test',
  366. 'filearea' => 'testarea',
  367. 'itemid' => 1
  368. ];
  369. $grades['userid'] = $u1->id;
  370. grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance,
  371. $gi->itemnumber, $grades);
  372. // Feedback file area.
  373. $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA);
  374. $this->assertEquals(2, count($files));
  375. // History file area.
  376. $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA);
  377. $this->assertEquals(2, count($files));
  378. $gg = grade_grade::fetch(array('userid' => $u1->id, 'itemid' => $gi->id));
  379. $gg->delete();
  380. // Feedback file area.
  381. $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA);
  382. $this->assertEquals(0, count($files));
  383. // History file area.
  384. $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA);
  385. $this->assertEquals(2, count($files));
  386. }
  387. /**
  388. * Creates a feedback file to copy to the gradebook area.
  389. */
  390. private function add_feedback_file_to_copy() {
  391. $dummy = array(
  392. 'contextid' => 1,
  393. 'component' => 'test',
  394. 'filearea' => 'testarea',
  395. 'itemid' => 1,
  396. 'filepath' => '/',
  397. 'filename' => 'feedback1.txt'
  398. );
  399. $fs = get_file_storage();
  400. $fs->create_file_from_string($dummy, '');
  401. }
  402. }