[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/availability/condition/completion/tests/ -> condition_test.php (source)

   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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1