/** * Tests the backup and restore of single activity to same course (duplicate) * when it contains availability conditions that depend on other items in * course. */ public function test_duplicate_availability() { global $DB, $CFG; $this->resetAfterTest(true); $this->setAdminUser(); $CFG->enableavailability = true; $CFG->enablecompletion = true; // Create a course with completion enabled and 2 forums. $generator = $this->getDataGenerator(); $course = $generator->create_course(array('format' => 'topics', 'enablecompletion' => COMPLETION_ENABLED)); $forum = $generator->create_module('forum', array('course' => $course->id)); $forum2 = $generator->create_module('forum', array('course' => $course->id, 'completion' => COMPLETION_TRACKING_MANUAL)); // We need a grade, easiest is to add an assignment. $assignrow = $generator->create_module('assign', array('course' => $course->id)); $assign = new assign(context_module::instance($assignrow->cmid), false, false); $item = $assign->get_grade_item(); // Make a test group and grouping as well. $group = $generator->create_group(array('courseid' => $course->id, 'name' => 'Group!')); $grouping = $generator->create_grouping(array('courseid' => $course->id, 'name' => 'Grouping!')); // Set the forum to have availability conditions on all those things, // plus some that don't exist or are special values. $availability = '{"op":"|","show":false,"c":[' . '{"type":"completion","cm":' . $forum2->cmid . ',"e":1},' . '{"type":"completion","cm":99999999,"e":1},' . '{"type":"grade","id":' . $item->id . ',"min":4,"max":94},' . '{"type":"grade","id":99999998,"min":4,"max":94},' . '{"type":"grouping","id":' . $grouping->id . '},' . '{"type":"grouping","id":99999997},' . '{"type":"group","id":' . $group->id . '},' . '{"type":"group"},' . '{"type":"group","id":99999996}' . ']}'; $DB->set_field('course_modules', 'availability', $availability, array('id' => $forum->cmid)); // Duplicate it. $newcmid = $this->duplicate($course, $forum->cmid); // For those which still exist on the course we expect it to keep using // the real ID. For those which do not exist on the course any more // (e.g. simulating backup/restore of single activity between 2 courses) // we expect the IDs to be replaced with marker value: 0 for cmid // and grade, -1 for group/grouping. $expected = str_replace(array('99999999', '99999998', '99999997', '99999996'), array(0, 0, -1, -1), $availability); // Check settings in new activity. $actual = $DB->get_field('course_modules', 'availability', array('id' => $newcmid)); $this->assertEquals($expected, $actual); }
/** * Format a column of data for display * * @param stdClass $row * @return string */ public function col_grademax(stdClass $row) { $gradeitem = $this->assignment->get_grade_item(); return format_float($this->assignment->get_instance()->grade, $gradeitem->get_decimals()); }
/** * Tests constructing and using grade condition. */ public function test_usage() { global $USER, $CFG; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $this->resetAfterTest(); $CFG->enableavailability = true; // Make a test course and user. $course = $this->getDataGenerator()->create_course(); $user = $this->getDataGenerator()->create_user(); $this->getDataGenerator()->enrol_user($user->id, $course->id); // Make assign module. $assignrow = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'name' => 'Test!')); $assign = new assign(context_module::instance($assignrow->cmid), false, false); $modinfo = get_fast_modinfo($course); $cm = $modinfo->get_cm($assignrow->cmid); $info = new \core_availability\info_module($cm); // Get the actual grade item. $item = $assign->get_grade_item(); // Construct tree with grade condition (any grade, specified item). $structure = (object) array('type' => 'grade', 'id' => (int) $item->id); $cond = new condition($structure); // Check if available (not available). $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~have a grade.*Test!~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Add grade and check available. self::set_grade($assignrow, $user->id, 37.2); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not have a grade.*Test!~', $information); // Construct directly and test remaining conditions; first, min grade (fail). self::set_grade($assignrow, $user->id, 29.99999); $structure->min = 30.0; $cond = new condition($structure); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~achieve a required score.*Test!~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Min grade (success). self::set_grade($assignrow, $user->id, 30); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not get certain scores.*Test!~', $information); // Max grade (fail). unset($structure->min); $structure->max = 30.0; $cond = new condition($structure); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~get an appropriate score.*Test!~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Max grade (success). self::set_grade($assignrow, $user->id, 29.99999); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not get certain scores.*Test!~', $information); // Max and min (fail). $structure->min = 30.0; $structure->max = 34.12345; $cond = new condition($structure); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $this->assertRegExp('~get a particular score.*Test!~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Still fail (other end). self::set_grade($assignrow, $user->id, 34.12345); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); // Success (top end). self::set_grade($assignrow, $user->id, 34.12344); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not get certain scores.*Test!~', $information); // Success (bottom end). self::set_grade($assignrow, $user->id, 30.0); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $this->assertRegExp('~do not get certain scores.*Test!~', $information); }
/** * Tests the is_available and get_description functions. */ public function test_usage() { global $CFG, $DB; require_once $CFG->dirroot . '/mod/assign/locallib.php'; $this->resetAfterTest(); // Create course with completion turned on. $CFG->enablecompletion = true; $CFG->enableavailability = true; $generator = $this->getDataGenerator(); $course = $generator->create_course(array('enablecompletion' => 1)); $user = $generator->create_user(); $generator->enrol_user($user->id, $course->id); $this->setUser($user); // Create a Page with manual completion for basic checks. $page = $generator->get_plugin_generator('mod_page')->create_instance(array('course' => $course->id, 'name' => 'Page!', 'completion' => COMPLETION_TRACKING_MANUAL)); // Create an assignment - we need to have something that can be graded // so as to test the PASS/FAIL states. Set it up to be completed based // on its grade item. $assignrow = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'name' => 'Assign!', 'completion' => COMPLETION_TRACKING_AUTOMATIC)); $DB->set_field('course_modules', 'completiongradeitemnumber', 0, array('id' => $assignrow->cmid)); $assign = new assign(context_module::instance($assignrow->cmid), false, false); // Get basic details. $modinfo = get_fast_modinfo($course); $pagecm = $modinfo->get_cm($page->cmid); $assigncm = $assign->get_course_module(); $info = new \core_availability\mock_info($course, $user->id); // COMPLETE state (false), positive and NOT. $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_COMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Page!.*is marked complete~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // INCOMPLETE state (true). $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_INCOMPLETE)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Page!.*is marked complete~', $information); // Mark page complete. $completion = new completion_info($course); $completion->update_state($pagecm, COMPLETION_COMPLETE); // COMPLETE state (true). $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_COMPLETE)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Page!.*is incomplete~', $information); // INCOMPLETE state (false). $cond = new condition((object) array('cm' => (int) $pagecm->id, 'e' => COMPLETION_INCOMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Page!.*is incomplete~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // We are going to need the grade item so that we can get pass/fails. $gradeitem = $assign->get_grade_item(); grade_object::set_properties($gradeitem, array('gradepass' => 50.0)); $gradeitem->update(); // With no grade, it should return true for INCOMPLETE and false for // the other three. $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Check $information for COMPLETE_PASS and _FAIL as we haven't yet. $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is complete and passed~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is complete and failed~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Change the grade to be complete and failed. self::set_grade($assignrow, $user->id, 40); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is complete and passed~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is not complete and failed~', $information); // Now change it to pass. self::set_grade($assignrow, $user->id, 60); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_INCOMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_PASS)); $this->assertTrue($cond->is_available(false, $info, true, $user->id)); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $information = $cond->get_description(false, true, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is not complete and passed~', $information); $cond = new condition((object) array('cm' => (int) $assigncm->id, 'e' => COMPLETION_COMPLETE_FAIL)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~Assign!.*is complete and failed~', $information); $this->assertTrue($cond->is_available(true, $info, true, $user->id)); // Simulate deletion of an activity by using an invalid cmid. These // conditions always fail, regardless of NOT flag or INCOMPLETE. $cond = new condition((object) array('cm' => $assigncm->id + 100, 'e' => COMPLETION_COMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); $information = $cond->get_description(false, false, $info); $information = \core_availability\info::format_info($information, $course); $this->assertRegExp('~(Missing activity).*is marked complete~', $information); $this->assertFalse($cond->is_available(true, $info, true, $user->id)); $cond = new condition((object) array('cm' => $assigncm->id + 100, 'e' => COMPLETION_INCOMPLETE)); $this->assertFalse($cond->is_available(false, $info, true, $user->id)); }