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 * Tests for class core_course_category 19 * 20 * @package core_course 21 * @category phpunit 22 * @copyright 2013 Marina Glancy 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26defined('MOODLE_INTERNAL') || die(); 27 28/** 29 * Functional test for class core_course_category 30 */ 31class core_course_category_testcase extends advanced_testcase { 32 33 protected $roles; 34 35 protected function setUp() { 36 parent::setUp(); 37 $this->resetAfterTest(); 38 $user = $this->getDataGenerator()->create_user(); 39 $this->setUser($user); 40 } 41 42 protected function get_roleid($context = null) { 43 global $USER; 44 if ($context === null) { 45 $context = context_system::instance(); 46 } 47 if (is_object($context)) { 48 $context = $context->id; 49 } 50 if (empty($this->roles)) { 51 $this->roles = array(); 52 } 53 if (empty($this->roles[$USER->id])) { 54 $this->roles[$USER->id] = array(); 55 } 56 if (empty($this->roles[$USER->id][$context])) { 57 $this->roles[$USER->id][$context] = create_role('Role for '.$USER->id.' in '.$context, 'role'.$USER->id.'-'.$context, '-'); 58 role_assign($this->roles[$USER->id][$context], $USER->id, $context); 59 } 60 return $this->roles[$USER->id][$context]; 61 } 62 63 protected function assign_capability($capability, $permission = CAP_ALLOW, $contextid = null) { 64 if ($contextid === null) { 65 $contextid = context_system::instance(); 66 } 67 if (is_object($contextid)) { 68 $contextid = $contextid->id; 69 } 70 assign_capability($capability, $permission, $this->get_roleid($contextid), $contextid, true); 71 accesslib_clear_all_caches_for_unit_testing(); 72 } 73 74 public function test_create_coursecat() { 75 // Create the category. 76 $data = new stdClass(); 77 $data->name = 'aaa'; 78 $data->description = 'aaa'; 79 $data->idnumber = ''; 80 81 $category1 = core_course_category::create($data); 82 83 // Initially confirm that base data was inserted correctly. 84 $this->assertSame($data->name, $category1->name); 85 $this->assertSame($data->description, $category1->description); 86 $this->assertSame($data->idnumber, $category1->idnumber); 87 88 $this->assertGreaterThanOrEqual(1, $category1->sortorder); 89 90 // Create two more categories and test the sortorder worked correctly. 91 $data->name = 'ccc'; 92 $category2 = core_course_category::create($data); 93 94 $data->name = 'bbb'; 95 $category3 = core_course_category::create($data); 96 97 $this->assertGreaterThan($category1->sortorder, $category2->sortorder); 98 $this->assertGreaterThan($category2->sortorder, $category3->sortorder); 99 } 100 101 public function test_name_idnumber_exceptions() { 102 try { 103 core_course_category::create(array('name' => '')); 104 $this->fail('Missing category name exception expected in core_course_category::create'); 105 } catch (moodle_exception $e) { 106 $this->assertInstanceOf('moodle_exception', $e); 107 } 108 $cat1 = core_course_category::create(array('name' => 'Cat1', 'idnumber' => '1')); 109 try { 110 $cat1->update(array('name' => '')); 111 $this->fail('Missing category name exception expected in core_course_category::update'); 112 } catch (moodle_exception $e) { 113 $this->assertInstanceOf('moodle_exception', $e); 114 } 115 try { 116 core_course_category::create(array('name' => 'Cat2', 'idnumber' => '1')); 117 $this->fail('Duplicate idnumber exception expected in core_course_category::create'); 118 } catch (moodle_exception $e) { 119 $this->assertInstanceOf('moodle_exception', $e); 120 } 121 $cat2 = core_course_category::create(array('name' => 'Cat2', 'idnumber' => '2')); 122 try { 123 $cat2->update(array('idnumber' => '1')); 124 $this->fail('Duplicate idnumber exception expected in core_course_category::update'); 125 } catch (moodle_exception $e) { 126 $this->assertInstanceOf('moodle_exception', $e); 127 } 128 // Test that duplicates with an idnumber of 0 cannot be created. 129 core_course_category::create(array('name' => 'Cat3', 'idnumber' => '0')); 130 try { 131 core_course_category::create(array('name' => 'Cat4', 'idnumber' => '0')); 132 $this->fail('Duplicate idnumber "0" exception expected in core_course_category::create'); 133 } catch (moodle_exception $e) { 134 $this->assertInstanceOf('moodle_exception', $e); 135 } 136 // Test an update cannot make a duplicate idnumber of 0. 137 try { 138 $cat2->update(array('idnumber' => '0')); 139 $this->fail('Duplicate idnumber "0" exception expected in core_course_category::update'); 140 } catch (Exception $e) { 141 $this->assertInstanceOf('moodle_exception', $e); 142 } 143 } 144 145 public function test_visibility() { 146 $this->assign_capability('moodle/category:viewhiddencategories'); 147 $this->assign_capability('moodle/category:manage'); 148 149 // Create category 1 initially hidden. 150 $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 0)); 151 $this->assertEquals(0, $category1->visible); 152 $this->assertEquals(0, $category1->visibleold); 153 154 // Create category 2 initially hidden as a child of hidden category 1. 155 $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0, 'parent' => $category1->id)); 156 $this->assertEquals(0, $category2->visible); 157 $this->assertEquals(0, $category2->visibleold); 158 159 // Create category 3 initially visible as a child of hidden category 1. 160 $category3 = core_course_category::create(array('name' => 'Cat3', 'visible' => 1, 'parent' => $category1->id)); 161 $this->assertEquals(0, $category3->visible); 162 $this->assertEquals(1, $category3->visibleold); 163 164 // Show category 1 and make sure that category 2 is hidden and category 3 is visible. 165 $category1->show(); 166 $this->assertEquals(1, core_course_category::get($category1->id)->visible); 167 $this->assertEquals(0, core_course_category::get($category2->id)->visible); 168 $this->assertEquals(1, core_course_category::get($category3->id)->visible); 169 170 // Create visible category 4. 171 $category4 = core_course_category::create(array('name' => 'Cat4')); 172 $this->assertEquals(1, $category4->visible); 173 $this->assertEquals(1, $category4->visibleold); 174 175 // Create visible category 5 as a child of visible category 4. 176 $category5 = core_course_category::create(array('name' => 'Cat5', 'parent' => $category4->id)); 177 $this->assertEquals(1, $category5->visible); 178 $this->assertEquals(1, $category5->visibleold); 179 180 // Hide category 4 and make sure category 5 is hidden too. 181 $category4->hide(); 182 $this->assertEquals(0, $category4->visible); 183 $this->assertEquals(0, $category4->visibleold); 184 $category5 = core_course_category::get($category5->id); // We have to re-read from DB. 185 $this->assertEquals(0, $category5->visible); 186 $this->assertEquals(1, $category5->visibleold); 187 188 // Show category 4 and make sure category 5 is visible too. 189 $category4->show(); 190 $this->assertEquals(1, $category4->visible); 191 $this->assertEquals(1, $category4->visibleold); 192 $category5 = core_course_category::get($category5->id); // We have to re-read from DB. 193 $this->assertEquals(1, $category5->visible); 194 $this->assertEquals(1, $category5->visibleold); 195 196 // Move category 5 under hidden category 2 and make sure it became hidden. 197 $category5->change_parent($category2->id); 198 $this->assertEquals(0, $category5->visible); 199 $this->assertEquals(1, $category5->visibleold); 200 201 // Re-read object for category 5 from DB and check again. 202 $category5 = core_course_category::get($category5->id); 203 $this->assertEquals(0, $category5->visible); 204 $this->assertEquals(1, $category5->visibleold); 205 206 // Rricky one! Move hidden category 5 under visible category ("Top") and make sure it is still hidden- 207 // WHY? Well, different people may expect different behaviour here. So better keep it hidden. 208 $category5->change_parent(0); 209 $this->assertEquals(0, $category5->visible); 210 $this->assertEquals(1, $category5->visibleold); 211 } 212 213 public function test_hierarchy() { 214 $this->assign_capability('moodle/category:viewhiddencategories'); 215 $this->assign_capability('moodle/category:manage'); 216 217 $category1 = core_course_category::create(array('name' => 'Cat1')); 218 $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 219 $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category1->id)); 220 $category4 = core_course_category::create(array('name' => 'Cat4', 'parent' => $category2->id)); 221 222 // Check function get_children(). 223 $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children())); 224 // Check function get_parents(). 225 $this->assertEquals(array($category1->id, $category2->id), $category4->get_parents()); 226 227 // Can not move category to itself or to it's children. 228 $this->assertFalse($category1->can_change_parent($category2->id)); 229 $this->assertFalse($category2->can_change_parent($category2->id)); 230 // Can move category to grandparent. 231 $this->assertTrue($category4->can_change_parent($category1->id)); 232 233 try { 234 $category2->change_parent($category4->id); 235 $this->fail('Exception expected - can not move category'); 236 } catch (moodle_exception $e) { 237 $this->assertInstanceOf('moodle_exception', $e); 238 } 239 240 $category4->change_parent(0); 241 $this->assertEquals(array(), $category4->get_parents()); 242 $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children())); 243 $this->assertEquals(array(), array_keys($category2->get_children())); 244 } 245 246 public function test_update() { 247 $category1 = core_course_category::create(array('name' => 'Cat1')); 248 $timecreated = $category1->timemodified; 249 $this->assertSame('Cat1', $category1->name); 250 $this->assertTrue(empty($category1->description)); 251 $this->waitForSecond(); 252 $testdescription = 'This is cat 1 а также русский текст'; 253 $category1->update(array('description' => $testdescription)); 254 $this->assertSame($testdescription, $category1->description); 255 $category1 = core_course_category::get($category1->id); 256 $this->assertSame($testdescription, $category1->description); 257 cache_helper::purge_by_event('changesincoursecat'); 258 $category1 = core_course_category::get($category1->id); 259 $this->assertSame($testdescription, $category1->description); 260 261 $this->assertGreaterThan($timecreated, $category1->timemodified); 262 } 263 264 public function test_delete() { 265 global $DB; 266 267 $this->assign_capability('moodle/category:manage'); 268 $this->assign_capability('moodle/course:create'); 269 270 $initialcatid = $DB->get_field_sql('SELECT max(id) from {course_categories}'); 271 272 $category1 = core_course_category::create(array('name' => 'Cat1')); 273 $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 274 $category3 = core_course_category::create(array('name' => 'Cat3')); 275 $category4 = core_course_category::create(array('name' => 'Cat4', 'parent' => $category2->id)); 276 277 $course1 = $this->getDataGenerator()->create_course(array('category' => $category2->id)); 278 $course2 = $this->getDataGenerator()->create_course(array('category' => $category4->id)); 279 $course3 = $this->getDataGenerator()->create_course(array('category' => $category4->id)); 280 $course4 = $this->getDataGenerator()->create_course(array('category' => $category1->id)); 281 282 // Now we have 283 // $category1 284 // $category2 285 // $category4 286 // $course2 287 // $course3 288 // $course1 289 // $course4 290 // $category3 291 // structure. 292 293 // Login as another user to test course:delete capability (user who created course can delete it within 24h even without cap). 294 $this->setUser($this->getDataGenerator()->create_user()); 295 296 // Delete category 2 and move content to category 3. 297 $this->assertFalse($category2->can_move_content_to($category3->id)); // No luck! 298 // Add necessary capabilities. 299 $this->assign_capability('moodle/course:create', CAP_ALLOW, context_coursecat::instance($category3->id)); 300 $this->assign_capability('moodle/category:manage'); 301 $this->assertTrue($category2->can_move_content_to($category3->id)); // Hurray! 302 $category2->delete_move($category3->id); 303 304 // Make sure we have: 305 // $category1 306 // $course4 307 // $category3 308 // $category4 309 // $course2 310 // $course3 311 // $course1 312 // structure. 313 314 $this->assertNull(core_course_category::get($category2->id, IGNORE_MISSING, true)); 315 $this->assertEquals(array(), $category1->get_children()); 316 $this->assertEquals(array($category4->id), array_keys($category3->get_children())); 317 $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course2->id))); 318 $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course3->id))); 319 $this->assertEquals($category3->id, $DB->get_field('course', 'category', array('id' => $course1->id))); 320 321 // Delete category 3 completely. 322 $this->assertFalse($category3->can_delete_full()); // No luck! 323 // Add necessary capabilities. 324 $this->assign_capability('moodle/course:delete', CAP_ALLOW, context_coursecat::instance($category3->id)); 325 $this->assertTrue($category3->can_delete_full()); // Hurray! 326 $category3->delete_full(); 327 328 // Make sure we have: 329 // $category1 330 // $course4 331 // structure. 332 333 // Note that we also have default 'Miscellaneous' category and default 'site' course. 334 $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course_categories} WHERE id > ?', array($initialcatid))); 335 $this->assertEquals($category1->id, $DB->get_field_sql('SELECT max(id) FROM {course_categories}')); 336 $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course} WHERE id <> ?', array(SITEID))); 337 $this->assertEquals(array('id' => $course4->id, 'category' => $category1->id), 338 (array)$DB->get_record_sql('SELECT id, category from {course} where id <> ?', array(SITEID))); 339 } 340 341 public function test_get_children() { 342 $category1 = core_course_category::create(array('name' => 'Cat1')); 343 $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 344 $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category1->id, 'visible' => 0)); 345 $category4 = core_course_category::create(array('name' => 'Cat4', 'idnumber' => '12', 'parent' => $category1->id)); 346 $category5 = core_course_category::create(array('name' => 'Cat5', 'idnumber' => '11', 347 'parent' => $category1->id, 'visible' => 0)); 348 $category6 = core_course_category::create(array('name' => 'Cat6', 'idnumber' => '10', 'parent' => $category1->id)); 349 $category7 = core_course_category::create(array('name' => 'Cat0', 'parent' => $category1->id)); 350 351 $children = $category1->get_children(); 352 // User does not have the capability to view hidden categories, so the list should be 353 // 2, 4, 6, 7. 354 $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children)); 355 $this->assertEquals(4, $category1->get_children_count()); 356 357 $children = $category1->get_children(array('offset' => 2)); 358 $this->assertEquals(array($category6->id, $category7->id), array_keys($children)); 359 $this->assertEquals(4, $category1->get_children_count()); 360 361 $children = $category1->get_children(array('limit' => 2)); 362 $this->assertEquals(array($category2->id, $category4->id), array_keys($children)); 363 364 $children = $category1->get_children(array('offset' => 1, 'limit' => 2)); 365 $this->assertEquals(array($category4->id, $category6->id), array_keys($children)); 366 367 $children = $category1->get_children(array('sort' => array('name' => 1))); 368 // Must be 7, 2, 4, 6. 369 $this->assertEquals(array($category7->id, $category2->id, $category4->id, $category6->id), array_keys($children)); 370 371 $children = $category1->get_children(array('sort' => array('idnumber' => 1, 'name' => -1))); 372 // Must be 2, 7, 6, 4. 373 $this->assertEquals(array($category2->id, $category7->id, $category6->id, $category4->id), array_keys($children)); 374 375 // Check that everything is all right after purging the caches. 376 cache_helper::purge_by_event('changesincoursecat'); 377 $children = $category1->get_children(); 378 $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children)); 379 $this->assertEquals(4, $category1->get_children_count()); 380 } 381 382 /** 383 * Test the get_all_children_ids function. 384 */ 385 public function test_get_all_children_ids() { 386 $category1 = core_course_category::create(array('name' => 'Cat1')); 387 $category2 = core_course_category::create(array('name' => 'Cat2')); 388 $category11 = core_course_category::create(array('name' => 'Cat11', 'parent' => $category1->id)); 389 $category12 = core_course_category::create(array('name' => 'Cat12', 'parent' => $category1->id)); 390 $category13 = core_course_category::create(array('name' => 'Cat13', 'parent' => $category1->id)); 391 $category111 = core_course_category::create(array('name' => 'Cat111', 'parent' => $category11->id)); 392 $category112 = core_course_category::create(array('name' => 'Cat112', 'parent' => $category11->id)); 393 $category1121 = core_course_category::create(array('name' => 'Cat1121', 'parent' => $category112->id)); 394 395 $this->assertCount(0, $category2->get_all_children_ids()); 396 $this->assertCount(6, $category1->get_all_children_ids()); 397 398 $cmpchildrencat1 = array($category11->id, $category12->id, $category13->id, $category111->id, $category112->id, 399 $category1121->id); 400 $childrencat1 = $category1->get_all_children_ids(); 401 // Order of values does not matter. Compare sorted arrays. 402 sort($cmpchildrencat1); 403 sort($childrencat1); 404 $this->assertEquals($cmpchildrencat1, $childrencat1); 405 406 $this->assertCount(3, $category11->get_all_children_ids()); 407 $this->assertCount(0, $category111->get_all_children_ids()); 408 $this->assertCount(1, $category112->get_all_children_ids()); 409 410 $this->assertEquals(array($category1121->id), $category112->get_all_children_ids()); 411 } 412 413 /** 414 * Test the countall function 415 */ 416 public function test_count_all() { 417 global $DB; 418 // Dont assume there is just one. An add-on might create a category as part of the install. 419 $numcategories = $DB->count_records('course_categories'); 420 $this->assertEquals($numcategories, core_course_category::count_all()); 421 $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' . 422 'core_course_category::is_simple_site()', DEBUG_DEVELOPER); 423 $category1 = core_course_category::create(array('name' => 'Cat1')); 424 $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id)); 425 $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category2->id, 'visible' => 0)); 426 // Now we've got three more. 427 $this->assertEquals($numcategories + 3, core_course_category::count_all()); 428 $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' . 429 'core_course_category::is_simple_site()', DEBUG_DEVELOPER); 430 cache_helper::purge_by_event('changesincoursecat'); 431 // We should still have 4. 432 $this->assertEquals($numcategories + 3, core_course_category::count_all()); 433 $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' . 434 'core_course_category::is_simple_site()', DEBUG_DEVELOPER); 435 } 436 437 /** 438 * Test the is_simple_site function 439 */ 440 public function test_is_simple_site() { 441 // By default site has one category and is considered simple. 442 $this->assertEquals(true, core_course_category::is_simple_site()); 443 $default = core_course_category::get_default(); 444 // When there is only one category but it is hidden, it is not a simple site. 445 $default->update(['visible' => 0]); 446 $this->assertEquals(false, core_course_category::is_simple_site()); 447 $default->update(['visible' => 1]); 448 $this->assertEquals(true, core_course_category::is_simple_site()); 449 // As soon as there is more than one category, site is not simple any more. 450 core_course_category::create(array('name' => 'Cat1')); 451 $this->assertEquals(false, core_course_category::is_simple_site()); 452 } 453 454 /** 455 * Test a categories ability to resort courses. 456 */ 457 public function test_resort_courses() { 458 $this->resetAfterTest(true); 459 $generator = $this->getDataGenerator(); 460 $category = $generator->create_category(); 461 $course1 = $generator->create_course(array( 462 'category' => $category->id, 463 'idnumber' => '006-01', 464 'shortname' => 'Biome Study', 465 'fullname' => '<span lang="ar" class="multilang">'.'دراسة منطقة إحيائية'.'</span><span lang="en" class="multilang">Biome Study</span>', 466 'timecreated' => '1000000001' 467 )); 468 $course2 = $generator->create_course(array( 469 'category' => $category->id, 470 'idnumber' => '007-02', 471 'shortname' => 'Chemistry Revision', 472 'fullname' => 'Chemistry Revision', 473 'timecreated' => '1000000002' 474 )); 475 $course3 = $generator->create_course(array( 476 'category' => $category->id, 477 'idnumber' => '007-03', 478 'shortname' => 'Swiss Rolls and Sunflowers', 479 'fullname' => 'Aarkvarks guide to Swiss Rolls and Sunflowers', 480 'timecreated' => '1000000003' 481 )); 482 $course4 = $generator->create_course(array( 483 'category' => $category->id, 484 'idnumber' => '006-04', 485 'shortname' => 'Scratch', 486 'fullname' => '<a href="test.php">Basic Scratch</a>', 487 'timecreated' => '1000000004' 488 )); 489 $c1 = (int)$course1->id; 490 $c2 = (int)$course2->id; 491 $c3 = (int)$course3->id; 492 $c4 = (int)$course4->id; 493 494 $coursecat = core_course_category::get($category->id); 495 $this->assertTrue($coursecat->resort_courses('idnumber')); 496 $this->assertSame(array($c1, $c4, $c2, $c3), array_keys($coursecat->get_courses())); 497 498 $this->assertTrue($coursecat->resort_courses('shortname')); 499 $this->assertSame(array($c1, $c2, $c4, $c3), array_keys($coursecat->get_courses())); 500 501 $this->assertTrue($coursecat->resort_courses('timecreated')); 502 $this->assertSame(array($c1, $c2, $c3, $c4), array_keys($coursecat->get_courses())); 503 504 try { 505 // Enable the multilang filter and set it to apply to headings and content. 506 filter_manager::reset_caches(); 507 filter_set_global_state('multilang', TEXTFILTER_ON); 508 filter_set_applies_to_strings('multilang', true); 509 $expected = array($c3, $c4, $c1, $c2); 510 } catch (coding_exception $ex) { 511 $expected = array($c3, $c4, $c2, $c1); 512 } 513 $this->assertTrue($coursecat->resort_courses('fullname')); 514 $this->assertSame($expected, array_keys($coursecat->get_courses())); 515 } 516 517 public function test_get_search_courses() { 518 $cat1 = core_course_category::create(array('name' => 'Cat1')); 519 $cat2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $cat1->id)); 520 $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3', 'summary' => ' ', 'idnumber' => 'ID3')); 521 $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 1', 'summary' => ' ', 'visible' => 0)); 522 $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Математика', 'summary' => ' Test ')); 523 $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 4', 'summary' => ' ', 'idnumber' => 'ID4')); 524 525 $c5 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 5', 'summary' => ' ')); 526 $c6 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Дискретная Математика', 'summary' => ' ')); 527 $c7 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 7', 'summary' => ' ', 'visible' => 0)); 528 $c8 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 8', 'summary' => ' ')); 529 530 // Get courses in category 1 (returned visible only because user is not enrolled). 531 $res = $cat1->get_courses(array('sortorder' => 1)); 532 $this->assertEquals(array($c4->id, $c3->id, $c1->id), array_keys($res)); // Courses are added in reverse order. 533 $this->assertEquals(3, $cat1->get_courses_count()); 534 535 // Get courses in category 1 recursively (returned visible only because user is not enrolled). 536 $res = $cat1->get_courses(array('recursive' => 1)); 537 $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c6->id, $c5->id), array_keys($res)); 538 $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1))); 539 540 // Get courses sorted by fullname. 541 $res = $cat1->get_courses(array('sort' => array('fullname' => 1))); 542 $this->assertEquals(array($c1->id, $c4->id, $c3->id), array_keys($res)); 543 $this->assertEquals(3, $cat1->get_courses_count(array('sort' => array('fullname' => 1)))); 544 545 // Get courses sorted by fullname recursively. 546 $res = $cat1->get_courses(array('recursive' => 1, 'sort' => array('fullname' => 1))); 547 $this->assertEquals(array($c1->id, $c4->id, $c5->id, $c8->id, $c6->id, $c3->id), array_keys($res)); 548 $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'sort' => array('fullname' => 1)))); 549 550 // Get courses sorted by fullname recursively, use offset and limit. 551 $res = $cat1->get_courses(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => -1))); 552 $this->assertEquals(array($c6->id, $c8->id), array_keys($res)); 553 // Offset and limit do not affect get_courses_count(). 554 $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => 1)))); 555 556 // Calling get_courses_count without prior call to get_courses(). 557 $this->assertEquals(3, $cat2->get_courses_count(array('recursive' => 1, 'sort' => array('idnumber' => 1)))); 558 559 // Search courses. 560 561 // Search by text. 562 $res = core_course_category::search_courses(array('search' => 'Test')); 563 $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); 564 $this->assertEquals(5, core_course_category::search_courses_count(array('search' => 'Test'))); 565 566 // Search by text with specified offset and limit. 567 $options = array('sort' => array('fullname' => 1), 'offset' => 1, 'limit' => 2); 568 $res = core_course_category::search_courses(array('search' => 'Test'), $options); 569 $this->assertEquals(array($c4->id, $c5->id), array_keys($res)); 570 $this->assertEquals(5, core_course_category::search_courses_count(array('search' => 'Test'), $options)); 571 572 // IMPORTANT: the tests below may fail on some databases 573 // case-insensitive search. 574 $res = core_course_category::search_courses(array('search' => 'test')); 575 $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res)); 576 $this->assertEquals(5, core_course_category::search_courses_count(array('search' => 'test'))); 577 578 // Non-latin language search. 579 $res = core_course_category::search_courses(array('search' => 'Математика')); 580 $this->assertEquals(array($c3->id, $c6->id), array_keys($res)); 581 $this->assertEquals(2, core_course_category::search_courses_count(array('search' => 'Математика'), array())); 582 583 $this->setUser($this->getDataGenerator()->create_user()); 584 585 // Add necessary capabilities. 586 $this->assign_capability('moodle/course:create', CAP_ALLOW, context_coursecat::instance($cat2->id)); 587 // Do another search with restricted capabilities. 588 $reqcaps = array('moodle/course:create'); 589 $res = core_course_category::search_courses(array('search' => 'test'), array(), $reqcaps); 590 $this->assertEquals(array($c8->id, $c5->id), array_keys($res)); 591 $this->assertEquals(2, core_course_category::search_courses_count(array('search' => 'test'), array(), $reqcaps)); 592 } 593 594 public function test_course_contacts() { 595 global $DB, $CFG; 596 597 set_config('coursecontactduplicates', false); 598 599 $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher')); 600 $managerrole = $DB->get_record('role', array('shortname'=>'manager')); 601 $studentrole = $DB->get_record('role', array('shortname'=>'student')); 602 $oldcoursecontact = $CFG->coursecontact; 603 604 $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id; 605 606 /* 607 * User is listed in course contacts for the course if he has one of the 608 * "course contact" roles ($CFG->coursecontact) AND is enrolled in the course. 609 * If the user has several roles only the highest is displayed. 610 */ 611 612 // Test case: 613 // 614 // == Cat1 (user2 has teacher role) 615 // == Cat2 616 // -- course21 (user2 is enrolled as manager) | [Expected] Manager: F2 L2 617 // -- course22 (user2 is enrolled as student) | [Expected] Teacher: F2 L2 618 // == Cat4 (user2 has manager role) 619 // -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | [Expected] Manager: F5 L5, Teacher: F4 L4 620 // -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2 621 // == Cat3 (user3 has manager role) 622 // -- course31 (user3 is enrolled as student) | [Expected] Manager: F3 L3 623 // -- course32 | [Expected] 624 // -- course11 (user1 is enrolled as teacher) | [Expected] Teacher: F1 L1 625 // -- course12 (user1 has teacher role) | [Expected] 626 // also user4 is enrolled as teacher but enrolment is not active 627 $category = $course = $enrol = $user = array(); 628 $category[1] = core_course_category::create(array('name' => 'Cat1'))->id; 629 $category[2] = core_course_category::create(array('name' => 'Cat2', 'parent' => $category[1]))->id; 630 $category[3] = core_course_category::create(array('name' => 'Cat3', 'parent' => $category[1]))->id; 631 $category[4] = core_course_category::create(array('name' => 'Cat4', 'parent' => $category[2]))->id; 632 foreach (array(1, 2, 3, 4) as $catid) { 633 foreach (array(1, 2) as $courseid) { 634 $course[$catid][$courseid] = $this->getDataGenerator()->create_course(array('idnumber' => 'id'.$catid.$courseid, 635 'category' => $category[$catid]))->id; 636 $enrol[$catid][$courseid] = $DB->get_record('enrol', array('courseid'=>$course[$catid][$courseid], 'enrol'=>'manual'), '*', MUST_EXIST); 637 } 638 } 639 foreach (array(1, 2, 3, 4, 5) as $userid) { 640 $user[$userid] = $this->getDataGenerator()->create_user(array('firstname' => 'F'.$userid, 'lastname' => 'L'.$userid))->id; 641 } 642 643 $manual = enrol_get_plugin('manual'); 644 645 // Nobody is enrolled now and course contacts are empty. 646 $allcourses = core_course_category::get(0)->get_courses( 647 array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1))); 648 foreach ($allcourses as $onecourse) { 649 $this->assertEmpty($onecourse->get_course_contacts()); 650 } 651 652 // Cat1 (user2 has teacher role) 653 role_assign($teacherrole->id, $user[2], context_coursecat::instance($category[1])); 654 // course21 (user2 is enrolled as manager) 655 $manual->enrol_user($enrol[2][1], $user[2], $managerrole->id); 656 // course22 (user2 is enrolled as student) 657 $manual->enrol_user($enrol[2][2], $user[2], $studentrole->id); 658 // Cat4 (user2 has manager role) 659 role_assign($managerrole->id, $user[2], context_coursecat::instance($category[4])); 660 // course41 (user4 is enrolled as teacher, user5 is enrolled as manager) 661 $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id); 662 $manual->enrol_user($enrol[4][1], $user[5], $managerrole->id); 663 // course42 (user2 is enrolled as teacher) 664 $manual->enrol_user($enrol[4][2], $user[2], $teacherrole->id); 665 // Cat3 (user3 has manager role) 666 role_assign($managerrole->id, $user[3], context_coursecat::instance($category[3])); 667 // course31 (user3 is enrolled as student) 668 $manual->enrol_user($enrol[3][1], $user[3], $studentrole->id); 669 // course11 (user1 is enrolled as teacher) 670 $manual->enrol_user($enrol[1][1], $user[1], $teacherrole->id); 671 // -- course12 (user1 has teacher role) 672 // also user4 is enrolled as teacher but enrolment is not active 673 role_assign($teacherrole->id, $user[1], context_course::instance($course[1][2])); 674 $manual->enrol_user($enrol[1][2], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED); 675 676 $allcourses = core_course_category::get(0)->get_courses( 677 array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1))); 678 // Simplify the list of contacts for each course (similar as renderer would do). 679 $contacts = array(); 680 foreach (array(1, 2, 3, 4) as $catid) { 681 foreach (array(1, 2) as $courseid) { 682 $tmp = array(); 683 foreach ($allcourses[$course[$catid][$courseid]]->get_course_contacts() as $contact) { 684 $tmp[] = $contact['rolename']. ': '. $contact['username']; 685 } 686 $contacts[$catid][$courseid] = join(', ', $tmp); 687 } 688 } 689 690 // Assert: 691 // -- course21 (user2 is enrolled as manager) | Manager: F2 L2 692 $this->assertSame('Manager: F2 L2', $contacts[2][1]); 693 // -- course22 (user2 is enrolled as student) | Teacher: F2 L2 694 $this->assertSame('Teacher: F2 L2', $contacts[2][2]); 695 // -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | Manager: F5 L5, Teacher: F4 L4 696 $this->assertSame('Manager: F5 L5, Teacher: F4 L4', $contacts[4][1]); 697 // -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2 698 $this->assertSame('Manager: F2 L2', $contacts[4][2]); 699 // -- course31 (user3 is enrolled as student) | Manager: F3 L3 700 $this->assertSame('Manager: F3 L3', $contacts[3][1]); 701 // -- course32 | 702 $this->assertSame('', $contacts[3][2]); 703 // -- course11 (user1 is enrolled as teacher) | Teacher: F1 L1 704 $this->assertSame('Teacher: F1 L1', $contacts[1][1]); 705 // -- course12 (user1 has teacher role) | 706 $this->assertSame('', $contacts[1][2]); 707 708 // Suspend user 4 and make sure he is no longer in contacts of course 1 in category 4. 709 $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED); 710 $allcourses = core_course_category::get(0)->get_courses(array( 711 'recursive' => true, 712 'coursecontacts' => true, 713 'sort' => array('idnumber' => 1)) 714 ); 715 $contacts = $allcourses[$course[4][1]]->get_course_contacts(); 716 $this->assertCount(1, $contacts); 717 $contact = reset($contacts); 718 $this->assertEquals('F5 L5', $contact['username']); 719 720 $CFG->coursecontact = $oldcoursecontact; 721 } 722 723 public function test_course_contacts_with_duplicates() { 724 global $DB, $CFG; 725 726 set_config('coursecontactduplicates', true); 727 728 $displayall = get_config('core', 'coursecontactduplicates'); 729 $this->assertEquals(true, $displayall); 730 731 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher')); 732 $managerrole = $DB->get_record('role', array('shortname' => 'manager')); 733 $studentrole = $DB->get_record('role', array('shortname' => 'student')); 734 $oldcoursecontact = $CFG->coursecontact; 735 736 $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id; 737 738 /* 739 * User is listed in course contacts for the course if he has one of the 740 * "course contact" roles ($CFG->coursecontact) AND is enrolled in the course. 741 * If the user has several roles all roles are displayed, but each role only once per user. 742 */ 743 744 /* 745 * Test case: 746 * 747 * == Cat1 (user2 has teacher role) 748 * == Cat2 749 * -- course21 (user2 is enrolled as manager) | [Expected] Manager: F2 L2 750 * -- course22 (user2 is enrolled as student) | [Expected] Teacher: F2 L2 751 * == Cat4 (user2 has manager role) 752 * -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) 753 * | [Expected] Manager: F5 L5, Teacher: F4 L4 754 * -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2 755 * == Cat3 (user3 has manager role) 756 * -- course31 (user3 is enrolled as student) | [Expected] Manager: F3 L3 757 * -- course32 | [Expected] 758 * -- course11 (user1 is enrolled as teacher) | [Expected] Teacher: F1 L1 759 * -- course12 (user1 has teacher role) | [Expected] 760 * also user4 is enrolled as teacher but enrolment is not active 761 */ 762 $category = $course = $enrol = $user = array(); 763 $category[1] = core_course_category::create(array('name' => 'Cat1'))->id; 764 $category[2] = core_course_category::create(array('name' => 'Cat2', 'parent' => $category[1]))->id; 765 $category[3] = core_course_category::create(array('name' => 'Cat3', 'parent' => $category[1]))->id; 766 $category[4] = core_course_category::create(array('name' => 'Cat4', 'parent' => $category[2]))->id; 767 foreach (array(1, 2, 3, 4) as $catid) { 768 foreach (array(1, 2) as $courseid) { 769 $course[$catid][$courseid] = $this->getDataGenerator()->create_course(array( 770 'idnumber' => 'id'.$catid.$courseid, 771 'category' => $category[$catid]) 772 )->id; 773 $enrol[$catid][$courseid] = $DB->get_record( 774 'enrol', 775 array('courseid' => $course[$catid][$courseid], 'enrol' => 'manual'), 776 '*', 777 MUST_EXIST 778 ); 779 } 780 } 781 foreach (array(1, 2, 3, 4, 5) as $userid) { 782 $user[$userid] = $this->getDataGenerator()->create_user(array( 783 'firstname' => 'F'.$userid, 784 'lastname' => 'L'.$userid) 785 )->id; 786 } 787 788 $manual = enrol_get_plugin('manual'); 789 790 // Nobody is enrolled now and course contacts are empty. 791 $allcourses = core_course_category::get(0)->get_courses(array( 792 'recursive' => true, 793 'coursecontacts' => true, 794 'sort' => array('idnumber' => 1)) 795 ); 796 foreach ($allcourses as $onecourse) { 797 $this->assertEmpty($onecourse->get_course_contacts()); 798 } 799 800 // Cat1: user2 has teacher role. 801 role_assign($teacherrole->id, $user[2], context_coursecat::instance($category[1])); 802 // Course21: user2 is enrolled as manager. 803 $manual->enrol_user($enrol[2][1], $user[2], $managerrole->id); 804 // Course22: user2 is enrolled as student. 805 $manual->enrol_user($enrol[2][2], $user[2], $studentrole->id); 806 // Cat4: user2 has manager role. 807 role_assign($managerrole->id, $user[2], context_coursecat::instance($category[4])); 808 // Course41: user4 is enrolled as teacher, user5 is enrolled as manager. 809 $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id); 810 $manual->enrol_user($enrol[4][1], $user[5], $managerrole->id); 811 // Course42: user2 is enrolled as teacher. 812 $manual->enrol_user($enrol[4][2], $user[2], $teacherrole->id); 813 // Cat3: user3 has manager role. 814 role_assign($managerrole->id, $user[3], context_coursecat::instance($category[3])); 815 // Course31: user3 is enrolled as student. 816 $manual->enrol_user($enrol[3][1], $user[3], $studentrole->id); 817 // Course11: user1 is enrolled as teacher and user4 is enrolled as teacher and has manager role. 818 $manual->enrol_user($enrol[1][1], $user[1], $teacherrole->id); 819 $manual->enrol_user($enrol[1][1], $user[4], $teacherrole->id); 820 role_assign($managerrole->id, $user[4], context_course::instance($course[1][1])); 821 // Course12: user1 has teacher role, but is not enrolled, as well as user4 is enrolled as teacher, but user4's enrolment is 822 // not active. 823 role_assign($teacherrole->id, $user[1], context_course::instance($course[1][2])); 824 $manual->enrol_user($enrol[1][2], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED); 825 826 $allcourses = core_course_category::get(0)->get_courses( 827 array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1))); 828 // Simplify the list of contacts for each course (similar as renderer would do). 829 $contacts = array(); 830 foreach (array(1, 2, 3, 4) as $catid) { 831 foreach (array(1, 2) as $courseid) { 832 $tmp = array(); 833 foreach ($allcourses[$course[$catid][$courseid]]->get_course_contacts() as $contact) { 834 $rolenames = array_map(function ($role) { 835 return $role->displayname; 836 }, $contact['roles']); 837 $tmp[] = implode(", ", $rolenames). ': '. 838 $contact['username']; 839 } 840 $contacts[$catid][$courseid] = join(', ', $tmp); 841 } 842 } 843 844 // Assert: 845 // Course21: user2 is enrolled as manager. [Expected] Manager: F2 L2, Teacher: F2 L2. 846 $this->assertSame('Manager, Teacher: F2 L2', $contacts[2][1]); 847 // Course22: user2 is enrolled as student. [Expected] Teacher: F2 L2. 848 $this->assertSame('Teacher: F2 L2', $contacts[2][2]); 849 // Course41: user4 is enrolled as teacher, user5 is enrolled as manager. [Expected] Manager: F5 L5, Teacher: F4 L4. 850 $this->assertSame('Manager: F5 L5, Teacher: F4 L4', $contacts[4][1]); 851 // Course42: user2 is enrolled as teacher. [Expected] Manager: F2 L2, Teacher: F2 L2. 852 $this->assertSame('Manager, Teacher: F2 L2', $contacts[4][2]); 853 // Course31: user3 is enrolled as student. [Expected] Manager: F3 L3. 854 $this->assertSame('Manager: F3 L3', $contacts[3][1]); 855 // Course32: nobody is enrolled. [Expected] (nothing). 856 $this->assertSame('', $contacts[3][2]); 857 // Course11: user1 is enrolled as teacher and user4 is enrolled as teacher and has manager role. [Expected] Manager: F4 L4, 858 // Teacher: F1 L1, Teacher: F4 L4. 859 $this->assertSame('Manager, Teacher: F4 L4, Teacher: F1 L1', $contacts[1][1]); 860 // Course12: user1 has teacher role, but is not enrolled, as well as user4 is enrolled as teacher, but user4's enrolment is 861 // not active. [Expected] (nothing). 862 $this->assertSame('', $contacts[1][2]); 863 864 // Suspend user 4 and make sure he is no longer in contacts of course 1 in category 4. 865 $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED); 866 $allcourses = core_course_category::get(0)->get_courses(array( 867 'recursive' => true, 868 'coursecontacts' => true, 869 'sort' => array('idnumber' => 1) 870 )); 871 $contacts = $allcourses[$course[4][1]]->get_course_contacts(); 872 $this->assertCount(1, $contacts); 873 $contact = reset($contacts); 874 $this->assertEquals('F5 L5', $contact['username']); 875 876 $CFG->coursecontact = $oldcoursecontact; 877 } 878 879 public function test_overview_files() { 880 global $CFG; 881 $this->setAdminUser(); 882 $cat1 = core_course_category::create(array('name' => 'Cat1')); 883 884 // Create course c1 with one image file. 885 $dratid1 = $this->fill_draft_area(array('filename.jpg' => 'Test file contents1')); 886 $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 887 'fullname' => 'Test 1', 'overviewfiles_filemanager' => $dratid1)); 888 // Create course c2 with two image files (only one file will be added because of settings). 889 $dratid2 = $this->fill_draft_area(array('filename21.jpg' => 'Test file contents21', 'filename22.jpg' => 'Test file contents22')); 890 $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 891 'fullname' => 'Test 2', 'overviewfiles_filemanager' => $dratid2)); 892 // Create course c3 without files. 893 $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3')); 894 895 // Change the settings to allow multiple files of any types. 896 $CFG->courseoverviewfileslimit = 3; 897 $CFG->courseoverviewfilesext = '*'; 898 // Create course c5 with two image files. 899 $dratid4 = $this->fill_draft_area(array('filename41.jpg' => 'Test file contents41', 'filename42.jpg' => 'Test file contents42')); 900 $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 901 'fullname' => 'Test 4', 'overviewfiles_filemanager' => $dratid4)); 902 // Create course c6 with non-image file. 903 $dratid5 = $this->fill_draft_area(array('filename51.zip' => 'Test file contents51')); 904 $c5 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 905 'fullname' => 'Test 5', 'overviewfiles_filemanager' => $dratid5)); 906 907 // Reset default settings. 908 $CFG->courseoverviewfileslimit = 1; 909 $CFG->courseoverviewfilesext = '.jpg,.gif,.png'; 910 911 $courses = $cat1->get_courses(); 912 $this->assertTrue($courses[$c1->id]->has_course_overviewfiles()); 913 $this->assertTrue($courses[$c2->id]->has_course_overviewfiles()); 914 $this->assertFalse($courses[$c3->id]->has_course_overviewfiles()); 915 $this->assertTrue($courses[$c4->id]->has_course_overviewfiles()); 916 $this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Does not validate the filetypes. 917 918 $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles())); 919 $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles())); 920 $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles())); 921 $this->assertEquals(1, count($courses[$c4->id]->get_course_overviewfiles())); 922 $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles())); // Validate the filetypes. 923 924 // Overview files are not allowed, all functions return empty values. 925 $CFG->courseoverviewfileslimit = 0; 926 927 $this->assertFalse($courses[$c1->id]->has_course_overviewfiles()); 928 $this->assertFalse($courses[$c2->id]->has_course_overviewfiles()); 929 $this->assertFalse($courses[$c3->id]->has_course_overviewfiles()); 930 $this->assertFalse($courses[$c4->id]->has_course_overviewfiles()); 931 $this->assertFalse($courses[$c5->id]->has_course_overviewfiles()); 932 933 $this->assertEquals(0, count($courses[$c1->id]->get_course_overviewfiles())); 934 $this->assertEquals(0, count($courses[$c2->id]->get_course_overviewfiles())); 935 $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles())); 936 $this->assertEquals(0, count($courses[$c4->id]->get_course_overviewfiles())); 937 $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles())); 938 939 // Multiple overview files are allowed but still limited to images. 940 $CFG->courseoverviewfileslimit = 3; 941 942 $this->assertTrue($courses[$c1->id]->has_course_overviewfiles()); 943 $this->assertTrue($courses[$c2->id]->has_course_overviewfiles()); 944 $this->assertFalse($courses[$c3->id]->has_course_overviewfiles()); 945 $this->assertTrue($courses[$c4->id]->has_course_overviewfiles()); 946 $this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Still does not validate the filetypes. 947 948 $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles())); 949 $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles())); // Only 1 file was actually added. 950 $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles())); 951 $this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles())); 952 $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles())); 953 954 // Multiple overview files of any type are allowed. 955 $CFG->courseoverviewfilesext = '*'; 956 957 $this->assertTrue($courses[$c1->id]->has_course_overviewfiles()); 958 $this->assertTrue($courses[$c2->id]->has_course_overviewfiles()); 959 $this->assertFalse($courses[$c3->id]->has_course_overviewfiles()); 960 $this->assertTrue($courses[$c4->id]->has_course_overviewfiles()); 961 $this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); 962 963 $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles())); 964 $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles())); 965 $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles())); 966 $this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles())); 967 $this->assertEquals(1, count($courses[$c5->id]->get_course_overviewfiles())); 968 } 969 970 public function test_get_nested_name() { 971 $cat1name = 'Cat1'; 972 $cat2name = 'Cat2'; 973 $cat3name = 'Cat3'; 974 $cat4name = 'Cat4'; 975 $category1 = core_course_category::create(array('name' => $cat1name)); 976 $category2 = core_course_category::create(array('name' => $cat2name, 'parent' => $category1->id)); 977 $category3 = core_course_category::create(array('name' => $cat3name, 'parent' => $category2->id)); 978 $category4 = core_course_category::create(array('name' => $cat4name, 'parent' => $category2->id)); 979 980 $this->assertEquals($cat1name, $category1->get_nested_name(false)); 981 $this->assertEquals("{$cat1name} / {$cat2name}", $category2->get_nested_name(false)); 982 $this->assertEquals("{$cat1name} / {$cat2name} / {$cat3name}", $category3->get_nested_name(false)); 983 $this->assertEquals("{$cat1name} / {$cat2name} / {$cat4name}", $category4->get_nested_name(false)); 984 } 985 986 public function test_coursecat_is_uservisible() { 987 global $USER; 988 989 // Create category 1 as visible. 990 $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1)); 991 // Create category 2 as hidden. 992 $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0)); 993 994 $this->assertTrue($category1->is_uservisible()); 995 $this->assertFalse($category2->is_uservisible()); 996 997 $this->assign_capability('moodle/category:viewhiddencategories'); 998 999 $this->assertTrue($category1->is_uservisible()); 1000 $this->assertTrue($category2->is_uservisible()); 1001 1002 // First, store current user's id, then login as another user. 1003 $userid = $USER->id; 1004 $this->setUser($this->getDataGenerator()->create_user()); 1005 1006 // User $user should still have the moodle/category:viewhiddencategories capability. 1007 $this->assertTrue($category1->is_uservisible($userid)); 1008 $this->assertTrue($category2->is_uservisible($userid)); 1009 1010 $this->assign_capability('moodle/category:viewhiddencategories', CAP_INHERIT); 1011 1012 $this->assertTrue($category1->is_uservisible()); 1013 $this->assertFalse($category2->is_uservisible()); 1014 } 1015 1016 public function test_current_user_coursecat_get() { 1017 $this->assign_capability('moodle/category:viewhiddencategories'); 1018 1019 // Create category 1 as visible. 1020 $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1)); 1021 // Create category 2 as hidden. 1022 $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0)); 1023 1024 $this->assertEquals($category1->id, core_course_category::get($category1->id)->id); 1025 $this->assertEquals($category2->id, core_course_category::get($category2->id)->id); 1026 1027 // Login as another user to test core_course_category::get. 1028 $this->setUser($this->getDataGenerator()->create_user()); 1029 $this->assertEquals($category1->id, core_course_category::get($category1->id)->id); 1030 1031 // Expecting to get an exception as this new user does not have the moodle/category:viewhiddencategories capability. 1032 $this->expectException('moodle_exception'); 1033 $this->expectExceptionMessage(get_string('cannotviewcategory', 'error')); 1034 core_course_category::get($category2->id); 1035 } 1036 1037 public function test_another_user_coursecat_get() { 1038 global $USER; 1039 1040 $this->assign_capability('moodle/category:viewhiddencategories'); 1041 1042 // Create category 1 as visible. 1043 $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1)); 1044 // Create category 2 as hidden. 1045 $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0)); 1046 1047 // First, store current user's object, then login as another user. 1048 $user1 = $USER; 1049 $user2 = $this->getDataGenerator()->create_user(); 1050 $this->setUser($user2); 1051 1052 $this->assertEquals($category1->id, core_course_category::get($category1->id, MUST_EXIST, false, $user1)->id); 1053 $this->assertEquals($category2->id, core_course_category::get($category2->id, MUST_EXIST, false, $user1)->id); 1054 1055 $this->setUser($user1); 1056 1057 $this->assertEquals($category1->id, core_course_category::get($category1->id, MUST_EXIST, false, $user2)->id); 1058 $this->expectException('moodle_exception'); 1059 $this->expectExceptionMessage(get_string('cannotviewcategory', 'error')); 1060 core_course_category::get($category2->id, MUST_EXIST, false, $user2); 1061 } 1062 1063 /** 1064 * Creates a draft area for current user and fills it with fake files 1065 * 1066 * @param array $files array of files that need to be added to filearea, filename => filecontents 1067 * @return int draftid for the filearea 1068 */ 1069 protected function fill_draft_area(array $files) { 1070 global $USER; 1071 $usercontext = context_user::instance($USER->id); 1072 $draftid = file_get_unused_draft_itemid(); 1073 foreach ($files as $filename => $filecontents) { 1074 // Add actual file there. 1075 $filerecord = array('component' => 'user', 'filearea' => 'draft', 1076 'contextid' => $usercontext->id, 'itemid' => $draftid, 1077 'filename' => $filename, 'filepath' => '/'); 1078 $fs = get_file_storage(); 1079 $fs->create_file_from_string($filerecord, $filecontents); 1080 } 1081 return $draftid; 1082 } 1083 1084 /** 1085 * This test ensures that is the list of courses in a category can be retrieved while a course is being deleted. 1086 */ 1087 public function test_get_courses_during_delete() { 1088 global $DB; 1089 $category = self::getDataGenerator()->create_category(); 1090 $course = self::getDataGenerator()->create_course(['category' => $category->id]); 1091 $othercourse = self::getDataGenerator()->create_course(['category' => $category->id]); 1092 $coursecategory = core_course_category::get($category->id); 1093 // Get a list of courses before deletion to populate the cache. 1094 $originalcourses = $coursecategory->get_courses(); 1095 $this->assertCount(2, $originalcourses); 1096 $this->assertArrayHasKey($course->id, $originalcourses); 1097 $this->assertArrayHasKey($othercourse->id, $originalcourses); 1098 // Simulate the course deletion process being part way though. 1099 $DB->delete_records('course', ['id' => $course->id]); 1100 // Get the list of courses while a deletion is in progress. 1101 $courses = $coursecategory->get_courses(); 1102 $this->assertCount(1, $courses); 1103 $this->assertArrayHasKey($othercourse->id, $courses); 1104 } 1105} 1106