[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 the completion condition. 19 * 20 * @package availability_completion 21 * @copyright 2014 The Open University 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 use availability_completion\condition; 28 29 global $CFG; 30 require_once($CFG->libdir . '/completionlib.php'); 31 32 /** 33 * Unit tests for the completion condition. 34 * 35 * @package availability_completion 36 * @copyright 2014 The Open University 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class availability_completion_condition_testcase extends advanced_testcase { 40 /** 41 * Load required classes. 42 */ 43 public function setUp() { 44 // Load the mock info class so that it can be used. 45 global $CFG; 46 require_once($CFG->dirroot . '/availability/tests/fixtures/mock_info.php'); 47 } 48 49 /** 50 * Tests constructing and using condition as part of tree. 51 */ 52 public function test_in_tree() { 53 global $USER, $CFG; 54 $this->resetAfterTest(); 55 56 $this->setAdminUser(); 57 58 // Create course with completion turned on and a Page. 59 $CFG->enablecompletion = true; 60 $CFG->enableavailability = true; 61 $generator = $this->getDataGenerator(); 62 $course = $generator->create_course(array('enablecompletion' => 1)); 63 $page = $generator->get_plugin_generator('mod_page')->create_instance( 64 array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); 65 66 $modinfo = get_fast_modinfo($course); 67 $cm = $modinfo->get_cm($page->cmid); 68 $info = new \core_availability\mock_info($course, $USER->id); 69 70 $structure = (object)array('op' => '|', 'show' => true, 'c' => array( 71 (object)array('type' => 'completion', 'cm' => (int)$cm->id, 72 'e' => COMPLETION_COMPLETE))); 73 $tree = new \core_availability\tree($structure); 74 75 // Initial check (user has not completed activity). 76 $result = $tree->check_available(false, $info, true, $USER->id); 77 $this->assertFalse($result->is_available()); 78 79 // Mark activity complete. 80 $completion = new completion_info($course); 81 $completion->update_state($cm, COMPLETION_COMPLETE); 82 83 // Now it's true! 84 $result = $tree->check_available(false, $info, true, $USER->id); 85 $this->assertTrue($result->is_available()); 86 } 87 88 /** 89 * Tests the constructor including error conditions. Also tests the 90 * string conversion feature (intended for debugging only). 91 */ 92 public function test_constructor() { 93 // No parameters. 94 $structure = new stdClass(); 95 try { 96 $cond = new condition($structure); 97 $this->fail(); 98 } catch (coding_exception $e) { 99 $this->assertContains('Missing or invalid ->cm', $e->getMessage()); 100 } 101 102 // Invalid $cm. 103 $structure->cm = 'hello'; 104 try { 105 $cond = new condition($structure); 106 $this->fail(); 107 } catch (coding_exception $e) { 108 $this->assertContains('Missing or invalid ->cm', $e->getMessage()); 109 } 110 111 // Missing $e. 112 $structure->cm = 42; 113 try { 114 $cond = new condition($structure); 115 $this->fail(); 116 } catch (coding_exception $e) { 117 $this->assertContains('Missing or invalid ->e', $e->getMessage()); 118 } 119 120 // Invalid $e. 121 $structure->e = 99; 122 try { 123 $cond = new condition($structure); 124 $this->fail(); 125 } catch (coding_exception $e) { 126 $this->assertContains('Missing or invalid ->e', $e->getMessage()); 127 } 128 129 // Successful construct & display with all different expected values. 130 $structure->e = COMPLETION_COMPLETE; 131 $cond = new condition($structure); 132 $this->assertEquals('{completion:cm42 COMPLETE}', (string)$cond); 133 134 $structure->e = COMPLETION_COMPLETE_PASS; 135 $cond = new condition($structure); 136 $this->assertEquals('{completion:cm42 COMPLETE_PASS}', (string)$cond); 137 138 $structure->e = COMPLETION_COMPLETE_FAIL; 139 $cond = new condition($structure); 140 $this->assertEquals('{completion:cm42 COMPLETE_FAIL}', (string)$cond); 141 142 $structure->e = COMPLETION_INCOMPLETE; 143 $cond = new condition($structure); 144 $this->assertEquals('{completion:cm42 INCOMPLETE}', (string)$cond); 145 } 146 147 /** 148 * Tests the save() function. 149 */ 150 public function test_save() { 151 $structure = (object)array('cm' => 42, 'e' => COMPLETION_COMPLETE); 152 $cond = new condition($structure); 153 $structure->type = 'completion'; 154 $this->assertEquals($structure, $cond->save()); 155 } 156 157 /** 158 * Tests the is_available and get_description functions. 159 */ 160 public function test_usage() { 161 global $CFG, $DB; 162 require_once($CFG->dirroot . '/mod/assign/locallib.php'); 163 $this->resetAfterTest(); 164 165 // Create course with completion turned on. 166 $CFG->enablecompletion = true; 167 $CFG->enableavailability = true; 168 $generator = $this->getDataGenerator(); 169 $course = $generator->create_course(array('enablecompletion' => 1)); 170 $user = $generator->create_user(); 171 $generator->enrol_user($user->id, $course->id); 172 $this->setUser($user); 173 174 // Create a Page with manual completion for basic checks. 175 $page = $generator->get_plugin_generator('mod_page')->create_instance( 176 array('course' => $course->id, 'name' => 'Page!', 177 'completion' => COMPLETION_TRACKING_MANUAL)); 178 179 // Create an assignment - we need to have something that can be graded 180 // so as to test the PASS/FAIL states. Set it up to be completed based 181 // on its grade item. 182 $assignrow = $this->getDataGenerator()->create_module('assign', array( 183 'course' => $course->id, 'name' => 'Assign!', 184 'completion' => COMPLETION_TRACKING_AUTOMATIC)); 185 $DB->set_field('course_modules', 'completiongradeitemnumber', 0, 186 array('id' => $assignrow->cmid)); 187 $assign = new assign(context_module::instance($assignrow->cmid), false, false); 188 189 // Get basic details. 190 $modinfo = get_fast_modinfo($course); 191 $pagecm = $modinfo->get_cm($page->cmid); 192 $assigncm = $assign->get_course_module(); 193 $info = new \core_availability\mock_info($course, $user->id); 194 195 // COMPLETE state (false), positive and NOT. 196 $cond = new condition((object)array( 197 'cm' => (int)$pagecm->id, 'e' => COMPLETION_COMPLETE)); 198 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 199 $information = $cond->get_description(false, false, $info); 200 $information = \core_availability\info::format_info($information, $course); 201 $this->assertRegExp('~Page!.*is marked complete~', $information); 202 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 203 204 // INCOMPLETE state (true). 205 $cond = new condition((object)array( 206 'cm' => (int)$pagecm->id, 'e' => COMPLETION_INCOMPLETE)); 207 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 208 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 209 $information = $cond->get_description(false, true, $info); 210 $information = \core_availability\info::format_info($information, $course); 211 $this->assertRegExp('~Page!.*is marked complete~', $information); 212 213 // Mark page complete. 214 $completion = new completion_info($course); 215 $completion->update_state($pagecm, COMPLETION_COMPLETE); 216 217 // COMPLETE state (true). 218 $cond = new condition((object)array( 219 'cm' => (int)$pagecm->id, 'e' => COMPLETION_COMPLETE)); 220 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 221 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 222 $information = $cond->get_description(false, true, $info); 223 $information = \core_availability\info::format_info($information, $course); 224 $this->assertRegExp('~Page!.*is incomplete~', $information); 225 226 // INCOMPLETE state (false). 227 $cond = new condition((object)array( 228 'cm' => (int)$pagecm->id, 'e' => COMPLETION_INCOMPLETE)); 229 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 230 $information = $cond->get_description(false, false, $info); 231 $information = \core_availability\info::format_info($information, $course); 232 $this->assertRegExp('~Page!.*is incomplete~', $information); 233 $this->assertTrue($cond->is_available(true, $info, 234 true, $user->id)); 235 236 // We are going to need the grade item so that we can get pass/fails. 237 $gradeitem = $assign->get_grade_item(); 238 grade_object::set_properties($gradeitem, array('gradepass' => 50.0)); 239 $gradeitem->update(); 240 241 // With no grade, it should return true for INCOMPLETE and false for 242 // the other three. 243 $cond = new condition((object)array( 244 'cm' => (int)$assigncm->id, 'e' => COMPLETION_INCOMPLETE)); 245 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 246 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 247 248 $cond = new condition((object)array( 249 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE)); 250 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 251 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 252 253 // Check $information for COMPLETE_PASS and _FAIL as we haven't yet. 254 $cond = new condition((object)array( 255 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); 256 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 257 $information = $cond->get_description(false, false, $info); 258 $information = \core_availability\info::format_info($information, $course); 259 $this->assertRegExp('~Assign!.*is complete and passed~', $information); 260 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 261 262 $cond = new condition((object)array( 263 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); 264 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 265 $information = $cond->get_description(false, false, $info); 266 $information = \core_availability\info::format_info($information, $course); 267 $this->assertRegExp('~Assign!.*is complete and failed~', $information); 268 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 269 270 // Change the grade to be complete and failed. 271 self::set_grade($assignrow, $user->id, 40); 272 273 $cond = new condition((object)array( 274 'cm' => (int)$assigncm->id, 'e' => COMPLETION_INCOMPLETE)); 275 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 276 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 277 278 $cond = new condition((object)array( 279 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE)); 280 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 281 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 282 283 $cond = new condition((object)array( 284 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); 285 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 286 $information = $cond->get_description(false, false, $info); 287 $information = \core_availability\info::format_info($information, $course); 288 $this->assertRegExp('~Assign!.*is complete and passed~', $information); 289 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 290 291 $cond = new condition((object)array( 292 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); 293 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 294 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 295 $information = $cond->get_description(false, true, $info); 296 $information = \core_availability\info::format_info($information, $course); 297 $this->assertRegExp('~Assign!.*is not complete and failed~', $information); 298 299 // Now change it to pass. 300 self::set_grade($assignrow, $user->id, 60); 301 302 $cond = new condition((object)array( 303 'cm' => (int)$assigncm->id, 'e' => COMPLETION_INCOMPLETE)); 304 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 305 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 306 307 $cond = new condition((object)array( 308 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE)); 309 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 310 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 311 312 $cond = new condition((object)array( 313 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); 314 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 315 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 316 $information = $cond->get_description(false, true, $info); 317 $information = \core_availability\info::format_info($information, $course); 318 $this->assertRegExp('~Assign!.*is not complete and passed~', $information); 319 320 $cond = new condition((object)array( 321 'cm' => (int)$assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); 322 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 323 $information = $cond->get_description(false, false, $info); 324 $information = \core_availability\info::format_info($information, $course); 325 $this->assertRegExp('~Assign!.*is complete and failed~', $information); 326 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 327 328 // Simulate deletion of an activity by using an invalid cmid. These 329 // conditions always fail, regardless of NOT flag or INCOMPLETE. 330 $cond = new condition((object)array( 331 'cm' => ($assigncm->id + 100), 'e' => COMPLETION_COMPLETE)); 332 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 333 $information = $cond->get_description(false, false, $info); 334 $information = \core_availability\info::format_info($information, $course); 335 $this->assertRegExp('~(Missing activity).*is marked complete~', $information); 336 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 337 $cond = new condition((object)array( 338 'cm' => ($assigncm->id + 100), 'e' => COMPLETION_INCOMPLETE)); 339 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 340 } 341 342 /** 343 * Tests completion_value_used static function. 344 */ 345 public function test_completion_value_used() { 346 global $CFG, $DB; 347 $this->resetAfterTest(); 348 349 // Create course with completion turned on and some sections. 350 $CFG->enablecompletion = true; 351 $CFG->enableavailability = true; 352 $generator = $this->getDataGenerator(); 353 $course = $generator->create_course( 354 array('numsections' => 1, 'enablecompletion' => 1), 355 array('createsections' => true)); 356 availability_completion\condition::wipe_static_cache(); 357 358 // Create three pages with manual completion. 359 $page1 = $generator->get_plugin_generator('mod_page')->create_instance( 360 array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); 361 $page2 = $generator->get_plugin_generator('mod_page')->create_instance( 362 array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); 363 $page3 = $generator->get_plugin_generator('mod_page')->create_instance( 364 array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); 365 366 // Set up page3 to depend on page1, and section1 to depend on page2. 367 $DB->set_field('course_modules', 'availability', 368 '{"op":"|","show":true,"c":[' . 369 '{"type":"completion","e":1,"cm":' . $page1->cmid . '}]}', 370 array('id' => $page3->cmid)); 371 $DB->set_field('course_sections', 'availability', 372 '{"op":"|","show":true,"c":[' . 373 '{"type":"completion","e":1,"cm":' . $page2->cmid . '}]}', 374 array('course' => $course->id, 'section' => 1)); 375 376 // Now check: nothing depends on page3 but something does on the others. 377 $this->assertTrue(availability_completion\condition::completion_value_used( 378 $course, $page1->cmid)); 379 $this->assertTrue(availability_completion\condition::completion_value_used( 380 $course, $page2->cmid)); 381 $this->assertFalse(availability_completion\condition::completion_value_used( 382 $course, $page3->cmid)); 383 } 384 385 /** 386 * Updates the grade of a user in the given assign module instance. 387 * 388 * @param stdClass $assignrow Assignment row from database 389 * @param int $userid User id 390 * @param float $grade Grade 391 */ 392 protected static function set_grade($assignrow, $userid, $grade) { 393 $grades = array(); 394 $grades[$userid] = (object)array( 395 'rawgrade' => $grade, 'userid' => $userid); 396 $assignrow->cmidnumber = null; 397 assign_grade_item_update($assignrow, $grades); 398 } 399 400 /** 401 * Tests the update_dependency_id() function. 402 */ 403 public function test_update_dependency_id() { 404 $cond = new condition((object)array( 405 'cm' => 123, 'e' => COMPLETION_COMPLETE)); 406 $this->assertFalse($cond->update_dependency_id('frogs', 123, 456)); 407 $this->assertFalse($cond->update_dependency_id('course_modules', 12, 34)); 408 $this->assertTrue($cond->update_dependency_id('course_modules', 123, 456)); 409 $after = $cond->save(); 410 $this->assertEquals(456, $after->cm); 411 } 412 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |