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 condition. 19 * 20 * @package availability_group 21 * @copyright 2014 The Open University 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25defined('MOODLE_INTERNAL') || die(); 26 27use availability_group\condition; 28 29/** 30 * Unit tests for the condition. 31 * 32 * @package availability_group 33 * @copyright 2014 The Open University 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36class availability_group_condition_testcase extends advanced_testcase { 37 /** 38 * Load required classes. 39 */ 40 public function setUp(): void { 41 // Load the mock info class so that it can be used. 42 global $CFG; 43 require_once($CFG->dirroot . '/availability/tests/fixtures/mock_info.php'); 44 } 45 46 /** 47 * Tests constructing and using condition. 48 */ 49 public function test_usage() { 50 global $CFG, $USER; 51 $this->resetAfterTest(); 52 $CFG->enableavailability = true; 53 54 // Erase static cache before test. 55 condition::wipe_static_cache(); 56 57 // Make a test course and user. 58 $generator = $this->getDataGenerator(); 59 $course = $generator->create_course(); 60 $user = $generator->create_user(); 61 $generator->enrol_user($user->id, $course->id); 62 $info = new \core_availability\mock_info($course, $user->id); 63 64 // Make 2 test groups, one in a grouping and one not. 65 $grouping = $generator->create_grouping(array('courseid' => $course->id)); 66 $group1 = $generator->create_group(array('courseid' => $course->id, 'name' => 'G1!')); 67 groups_assign_grouping($grouping->id, $group1->id); 68 $group2 = $generator->create_group(array('courseid' => $course->id, 'name' => 'G2!')); 69 70 // Do test (not in group). 71 $cond = new condition((object)array('id' => (int)$group1->id)); 72 73 // Check if available (when not available). 74 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 75 $information = $cond->get_description(false, false, $info); 76 $information = \core_availability\info::format_info($information, $course); 77 $this->assertMatchesRegularExpression('~You belong to.*G1!~', $information); 78 $this->assertTrue($cond->is_available(true, $info, true, $user->id)); 79 80 // Add user to groups and refresh cache. 81 groups_add_member($group1, $user); 82 groups_add_member($group2, $user); 83 get_fast_modinfo($course->id, 0, true); 84 85 // Recheck. 86 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 87 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 88 $information = $cond->get_description(false, true, $info); 89 $information = \core_availability\info::format_info($information, $course); 90 $this->assertMatchesRegularExpression('~do not belong to.*G1!~', $information); 91 92 // Check group 2 works also. 93 $cond = new condition((object)array('id' => (int)$group2->id)); 94 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 95 96 // What about an 'any group' condition? 97 $cond = new condition((object)array()); 98 $this->assertTrue($cond->is_available(false, $info, true, $user->id)); 99 $this->assertFalse($cond->is_available(true, $info, true, $user->id)); 100 $information = $cond->get_description(false, true, $info); 101 $information = \core_availability\info::format_info($information, $course); 102 $this->assertMatchesRegularExpression('~do not belong to any~', $information); 103 104 // Admin user doesn't belong to a group, but they can access it 105 // either way (positive or NOT). 106 $this->setAdminUser(); 107 $this->assertTrue($cond->is_available(false, $info, true, $USER->id)); 108 $this->assertTrue($cond->is_available(true, $info, true, $USER->id)); 109 110 // Group that doesn't exist uses 'missing' text. 111 $cond = new condition((object)array('id' => $group2->id + 1000)); 112 $this->assertFalse($cond->is_available(false, $info, true, $user->id)); 113 $information = $cond->get_description(false, false, $info); 114 $information = \core_availability\info::format_info($information, $course); 115 $this->assertMatchesRegularExpression('~You belong to.*\(Missing group\)~', $information); 116 } 117 118 /** 119 * Tests the constructor including error conditions. Also tests the 120 * string conversion feature (intended for debugging only). 121 */ 122 public function test_constructor() { 123 // Invalid id (not int). 124 $structure = (object)array('id' => 'bourne'); 125 try { 126 $cond = new condition($structure); 127 $this->fail(); 128 } catch (coding_exception $e) { 129 $this->assertStringContainsString('Invalid ->id', $e->getMessage()); 130 } 131 132 // Valid (with id). 133 $structure->id = 123; 134 $cond = new condition($structure); 135 $this->assertEquals('{group:#123}', (string)$cond); 136 137 // Valid (no id). 138 unset($structure->id); 139 $cond = new condition($structure); 140 $this->assertEquals('{group:any}', (string)$cond); 141 } 142 143 /** 144 * Tests the save() function. 145 */ 146 public function test_save() { 147 $structure = (object)array('id' => 123); 148 $cond = new condition($structure); 149 $structure->type = 'group'; 150 $this->assertEquals($structure, $cond->save()); 151 152 $structure = (object)array(); 153 $cond = new condition($structure); 154 $structure->type = 'group'; 155 $this->assertEquals($structure, $cond->save()); 156 } 157 158 /** 159 * Tests the update_dependency_id() function. 160 */ 161 public function test_update_dependency_id() { 162 $cond = new condition((object)array('id' => 123)); 163 $this->assertFalse($cond->update_dependency_id('frogs', 123, 456)); 164 $this->assertFalse($cond->update_dependency_id('groups', 12, 34)); 165 $this->assertTrue($cond->update_dependency_id('groups', 123, 456)); 166 $after = $cond->save(); 167 $this->assertEquals(456, $after->id); 168 } 169 170 /** 171 * Tests the filter_users (bulk checking) function. Also tests the SQL 172 * variant get_user_list_sql. 173 */ 174 public function test_filter_users() { 175 global $DB; 176 $this->resetAfterTest(); 177 178 // Erase static cache before test. 179 condition::wipe_static_cache(); 180 181 // Make a test course and some users. 182 $generator = $this->getDataGenerator(); 183 $course = $generator->create_course(); 184 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); 185 $teacher = $generator->create_user(); 186 $generator->enrol_user($teacher->id, $course->id, $roleids['editingteacher']); 187 $allusers = array($teacher->id => $teacher); 188 $students = array(); 189 for ($i = 0; $i < 3; $i++) { 190 $student = $generator->create_user(); 191 $students[$i] = $student; 192 $generator->enrol_user($student->id, $course->id, $roleids['student']); 193 $allusers[$student->id] = $student; 194 } 195 $info = new \core_availability\mock_info($course); 196 197 // Make test groups. 198 $group1 = $generator->create_group(array('courseid' => $course->id)); 199 $group2 = $generator->create_group(array('courseid' => $course->id)); 200 201 // Assign students to groups as follows (teacher is not in a group): 202 // 0: no groups. 203 // 1: in group 1. 204 // 2: in group 2. 205 groups_add_member($group1, $students[1]); 206 groups_add_member($group2, $students[2]); 207 208 // Test 'any group' condition. 209 $checker = new \core_availability\capability_checker($info->get_context()); 210 $cond = new condition((object)array()); 211 $result = array_keys($cond->filter_user_list($allusers, false, $info, $checker)); 212 ksort($result); 213 $expected = array($teacher->id, $students[1]->id, $students[2]->id); 214 $this->assertEquals($expected, $result); 215 216 // Test it with get_user_list_sql. 217 list ($sql, $params) = $cond->get_user_list_sql(false, $info, true); 218 $result = $DB->get_fieldset_sql($sql, $params); 219 sort($result); 220 $this->assertEquals($expected, $result); 221 222 // Test NOT version (note that teacher can still access because AAG works 223 // both ways). 224 $result = array_keys($cond->filter_user_list($allusers, true, $info, $checker)); 225 ksort($result); 226 $expected = array($teacher->id, $students[0]->id); 227 $this->assertEquals($expected, $result); 228 229 // Test with get_user_list_sql. 230 list ($sql, $params) = $cond->get_user_list_sql(true, $info, true); 231 $result = $DB->get_fieldset_sql($sql, $params); 232 sort($result); 233 $this->assertEquals($expected, $result); 234 235 // Test specific group. 236 $cond = new condition((object)array('id' => (int)$group1->id)); 237 $result = array_keys($cond->filter_user_list($allusers, false, $info, $checker)); 238 ksort($result); 239 $expected = array($teacher->id, $students[1]->id); 240 $this->assertEquals($expected, $result); 241 242 list ($sql, $params) = $cond->get_user_list_sql(false, $info, true); 243 $result = $DB->get_fieldset_sql($sql, $params); 244 sort($result); 245 $this->assertEquals($expected, $result); 246 247 $result = array_keys($cond->filter_user_list($allusers, true, $info, $checker)); 248 ksort($result); 249 $expected = array($teacher->id, $students[0]->id, $students[2]->id); 250 $this->assertEquals($expected, $result); 251 252 list ($sql, $params) = $cond->get_user_list_sql(true, $info, true); 253 $result = $DB->get_fieldset_sql($sql, $params); 254 sort($result); 255 $this->assertEquals($expected, $result); 256 } 257} 258