Merge branch 'MDL-72498' of git://github.com/paulholden/moodle
[moodle.git] / course / tests / category_test.php
blob9ed5fb9c00e53c9c0557148964d06d0e2e80bcb6
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.
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/>.
17 /**
18 * Tests for class core_course_category
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
26 defined('MOODLE_INTERNAL') || die();
28 /**
29 * Functional test for class core_course_category
31 class core_course_category_testcase extends advanced_testcase {
33 protected $roles;
35 protected function setUp(): void {
36 parent::setUp();
37 $this->resetAfterTest();
38 $user = $this->getDataGenerator()->create_user();
39 $this->setUser($user);
42 protected function get_roleid($context = null) {
43 global $USER;
44 if ($context === null) {
45 $context = context_system::instance();
47 if (is_object($context)) {
48 $context = $context->id;
50 if (empty($this->roles)) {
51 $this->roles = array();
53 if (empty($this->roles[$USER->id])) {
54 $this->roles[$USER->id] = array();
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);
60 return $this->roles[$USER->id][$context];
63 protected function assign_capability($capability, $permission = CAP_ALLOW, $contextid = null) {
64 if ($contextid === null) {
65 $contextid = context_system::instance();
67 if (is_object($contextid)) {
68 $contextid = $contextid->id;
70 assign_capability($capability, $permission, $this->get_roleid($contextid), $contextid, true);
71 accesslib_clear_all_caches_for_unit_testing();
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 = '';
81 $category1 = core_course_category::create($data);
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);
88 $this->assertGreaterThanOrEqual(1, $category1->sortorder);
90 // Create two more categories and test the sortorder worked correctly.
91 $data->name = 'ccc';
92 $category2 = core_course_category::create($data);
94 $data->name = 'bbb';
95 $category3 = core_course_category::create($data);
97 $this->assertGreaterThan($category1->sortorder, $category2->sortorder);
98 $this->assertGreaterThan($category2->sortorder, $category3->sortorder);
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);
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);
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);
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);
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);
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);
145 public function test_visibility() {
146 $this->assign_capability('moodle/category:viewhiddencategories');
147 $this->assign_capability('moodle/category:manage');
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
213 public function test_hierarchy() {
214 $this->assign_capability('moodle/category:viewhiddencategories');
215 $this->assign_capability('moodle/category:manage');
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));
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());
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));
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);
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()));
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);
261 $this->assertGreaterThan($timecreated, $category1->timemodified);
264 public function test_delete() {
265 global $DB;
267 $this->assign_capability('moodle/category:manage');
268 $this->assign_capability('moodle/course:create');
270 $initialcatid = $DB->get_field_sql('SELECT max(id) from {course_categories}');
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));
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));
282 // Now we have
283 // $category1
284 // $category2
285 // $category4
286 // $course2
287 // $course3
288 // $course1
289 // $course4
290 // $category3
291 // structure.
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());
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);
304 // Make sure we have:
305 // $category1
306 // $course4
307 // $category3
308 // $category4
309 // $course2
310 // $course3
311 // $course1
312 // structure.
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)));
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();
328 // Make sure we have:
329 // $category1
330 // $course4
331 // structure.
333 // Note that we also have default course 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)));
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));
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());
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());
361 $children = $category1->get_children(array('limit' => 2));
362 $this->assertEquals(array($category2->id, $category4->id), array_keys($children));
364 $children = $category1->get_children(array('offset' => 1, 'limit' => 2));
365 $this->assertEquals(array($category4->id, $category6->id), array_keys($children));
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));
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));
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());
383 * Test the get_all_children_ids function.
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));
395 $this->assertCount(0, $category2->get_all_children_ids());
396 $this->assertCount(6, $category1->get_all_children_ids());
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);
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());
410 $this->assertEquals(array($category1121->id), $category112->get_all_children_ids());
414 * Test the countall function
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);
438 * Test the is_simple_site function
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());
455 * Test a categories ability to resort courses.
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'
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'
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'
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'
489 $c1 = (int)$course1->id;
490 $c2 = (int)$course2->id;
491 $c3 = (int)$course3->id;
492 $c4 = (int)$course4->id;
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()));
498 $this->assertTrue($coursecat->resort_courses('shortname'));
499 $this->assertSame(array($c1, $c2, $c4, $c3), array_keys($coursecat->get_courses()));
501 $this->assertTrue($coursecat->resort_courses('timecreated'));
502 $this->assertSame(array($c1, $c2, $c3, $c4), array_keys($coursecat->get_courses()));
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);
513 $this->assertTrue($coursecat->resort_courses('fullname'));
514 $this->assertSame($expected, array_keys($coursecat->get_courses()));
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'));
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' => ' '));
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());
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)));
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))));
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))));
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))));
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))));
559 // Search courses.
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')));
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));
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')));
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()));
583 $this->setUser($this->getDataGenerator()->create_user());
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));
594 public function test_course_contacts() {
595 global $DB, $CFG;
597 set_config('coursecontactduplicates', false);
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;
604 $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id;
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.
612 // Test case:
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);
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;
643 $manual = enrol_get_plugin('manual');
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());
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);
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'];
686 $contacts[$catid][$courseid] = join(', ', $tmp);
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]);
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))
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']);
720 $CFG->coursecontact = $oldcoursecontact;
723 public function test_course_contacts_with_duplicates() {
724 global $DB, $CFG;
726 set_config('coursecontactduplicates', true);
728 $displayall = get_config('core', 'coursecontactduplicates');
729 $this->assertEquals(true, $displayall);
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;
736 $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id;
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.
745 * Test case:
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
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
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;
788 $manual = enrol_get_plugin('manual');
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))
796 foreach ($allcourses as $onecourse) {
797 $this->assertEmpty($onecourse->get_course_contacts());
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);
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'];
840 $contacts[$catid][$courseid] = join(', ', $tmp);
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]);
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)
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']);
876 $CFG->coursecontact = $oldcoursecontact;
879 public function test_overview_files() {
880 global $CFG;
881 $this->setAdminUser();
882 $cat1 = core_course_category::create(array('name' => 'Cat1'));
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'));
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));
907 // Reset default settings.
908 $CFG->courseoverviewfileslimit = 1;
909 $CFG->courseoverviewfilesext = 'web_image';
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.
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.
924 // Overview files are not allowed, all functions return empty values.
925 $CFG->courseoverviewfileslimit = 0;
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());
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()));
939 // Multiple overview files are allowed but still limited to images.
940 $CFG->courseoverviewfileslimit = 3;
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.
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()));
954 // Multiple overview files of any type are allowed.
955 $CFG->courseoverviewfilesext = '*';
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());
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()));
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));
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));
986 public function test_coursecat_is_uservisible() {
987 global $USER;
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));
994 $this->assertTrue($category1->is_uservisible());
995 $this->assertFalse($category2->is_uservisible());
997 $this->assign_capability('moodle/category:viewhiddencategories');
999 $this->assertTrue($category1->is_uservisible());
1000 $this->assertTrue($category2->is_uservisible());
1002 // First, store current user's id, then login as another user.
1003 $userid = $USER->id;
1004 $this->setUser($this->getDataGenerator()->create_user());
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));
1010 $this->assign_capability('moodle/category:viewhiddencategories', CAP_INHERIT);
1012 $this->assertTrue($category1->is_uservisible());
1013 $this->assertFalse($category2->is_uservisible());
1016 public function test_current_user_coursecat_get() {
1017 $this->assign_capability('moodle/category:viewhiddencategories');
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));
1024 $this->assertEquals($category1->id, core_course_category::get($category1->id)->id);
1025 $this->assertEquals($category2->id, core_course_category::get($category2->id)->id);
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);
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);
1037 public function test_another_user_coursecat_get() {
1038 global $USER;
1040 $this->assign_capability('moodle/category:viewhiddencategories');
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));
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);
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);
1055 $this->setUser($user1);
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);
1064 * Creates a draft area for current user and fills it with fake files
1066 * @param array $files array of files that need to be added to filearea, filename => filecontents
1067 * @return int draftid for the filearea
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);
1081 return $draftid;
1085 * This test ensures that is the list of courses in a category can be retrieved while a course is being deleted.
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);