Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
namespace core_course;
18
 
19
use core_course_category;
20
 
21
/**
22
 * Tests for class core_course_category
23
 *
24
 * @package    core_course
25
 * @category   test
26
 * @copyright  2013 Marina Glancy
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 */
29
class category_test extends \advanced_testcase {
30
 
31
    protected $roles;
32
 
33
    protected function setUp(): void {
34
        parent::setUp();
35
        $this->resetAfterTest();
36
        $user = $this->getDataGenerator()->create_user();
37
        $this->setUser($user);
38
    }
39
 
40
    protected function get_roleid($context = null) {
41
        global $USER;
42
        if ($context === null) {
43
            $context = \context_system::instance();
44
        }
45
        if (is_object($context)) {
46
            $context = $context->id;
47
        }
48
        if (empty($this->roles)) {
49
            $this->roles = array();
50
        }
51
        if (empty($this->roles[$USER->id])) {
52
            $this->roles[$USER->id] = array();
53
        }
54
        if (empty($this->roles[$USER->id][$context])) {
55
            $this->roles[$USER->id][$context] = create_role('Role for '.$USER->id.' in '.$context, 'role'.$USER->id.'-'.$context, '-');
56
            role_assign($this->roles[$USER->id][$context], $USER->id, $context);
57
        }
58
        return $this->roles[$USER->id][$context];
59
    }
60
 
61
    protected function assign_capability($capability, $permission = CAP_ALLOW, $contextid = null) {
62
        if ($contextid === null) {
63
            $contextid = \context_system::instance();
64
        }
65
        if (is_object($contextid)) {
66
            $contextid = $contextid->id;
67
        }
68
        assign_capability($capability, $permission, $this->get_roleid($contextid), $contextid, true);
69
        accesslib_clear_all_caches_for_unit_testing();
70
    }
71
 
72
    public function test_create_coursecat() {
73
        // Create the category.
74
        $data = new \stdClass();
75
        $data->name = 'aaa';
76
        $data->description = 'aaa';
77
        $data->idnumber = '';
78
 
79
        $category1 = core_course_category::create($data);
80
 
81
        // Initially confirm that base data was inserted correctly.
82
        $this->assertSame($data->name, $category1->name);
83
        $this->assertSame($data->description, $category1->description);
84
        $this->assertSame($data->idnumber, $category1->idnumber);
85
 
86
        $this->assertGreaterThanOrEqual(1, $category1->sortorder);
87
 
88
        // Create two more categories and test the sortorder worked correctly.
89
        $data->name = 'ccc';
90
        $category2 = core_course_category::create($data);
91
 
92
        $data->name = 'bbb';
93
        $category3 = core_course_category::create($data);
94
 
95
        $this->assertGreaterThan($category1->sortorder, $category2->sortorder);
96
        $this->assertGreaterThan($category2->sortorder, $category3->sortorder);
97
    }
98
 
99
    public function test_name_idnumber_exceptions() {
100
        try {
101
            core_course_category::create(array('name' => ''));
102
            $this->fail('Missing category name exception expected in core_course_category::create');
103
        } catch (\moodle_exception $e) {
104
            $this->assertInstanceOf('moodle_exception', $e);
105
        }
106
        $cat1 = core_course_category::create(array('name' => 'Cat1', 'idnumber' => '1'));
107
        try {
108
            $cat1->update(array('name' => ''));
109
            $this->fail('Missing category name exception expected in core_course_category::update');
110
        } catch (\moodle_exception $e) {
111
            $this->assertInstanceOf('moodle_exception', $e);
112
        }
113
        try {
114
            core_course_category::create(array('name' => 'Cat2', 'idnumber' => '1'));
115
            $this->fail('Duplicate idnumber exception expected in core_course_category::create');
116
        } catch (\moodle_exception $e) {
117
            $this->assertInstanceOf('moodle_exception', $e);
118
        }
119
        $cat2 = core_course_category::create(array('name' => 'Cat2', 'idnumber' => '2'));
120
        try {
121
            $cat2->update(array('idnumber' => '1'));
122
            $this->fail('Duplicate idnumber exception expected in core_course_category::update');
123
        } catch (\moodle_exception $e) {
124
            $this->assertInstanceOf('moodle_exception', $e);
125
        }
126
        // Test that duplicates with an idnumber of 0 cannot be created.
127
        core_course_category::create(array('name' => 'Cat3', 'idnumber' => '0'));
128
        try {
129
            core_course_category::create(array('name' => 'Cat4', 'idnumber' => '0'));
130
            $this->fail('Duplicate idnumber "0" exception expected in core_course_category::create');
131
        } catch (\moodle_exception $e) {
132
            $this->assertInstanceOf('moodle_exception', $e);
133
        }
134
        // Test an update cannot make a duplicate idnumber of 0.
135
        try {
136
            $cat2->update(array('idnumber' => '0'));
137
            $this->fail('Duplicate idnumber "0" exception expected in core_course_category::update');
138
        } catch (\Exception $e) {
139
            $this->assertInstanceOf('moodle_exception', $e);
140
        }
141
    }
142
 
143
    public function test_visibility() {
144
        $this->assign_capability('moodle/category:viewhiddencategories');
145
        $this->assign_capability('moodle/category:manage');
146
 
147
        // Create category 1 initially hidden.
148
        $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 0));
149
        $this->assertEquals(0, $category1->visible);
150
        $this->assertEquals(0, $category1->visibleold);
151
 
152
        // Create category 2 initially hidden as a child of hidden category 1.
153
        $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0, 'parent' => $category1->id));
154
        $this->assertEquals(0, $category2->visible);
155
        $this->assertEquals(0, $category2->visibleold);
156
 
157
        // Create category 3 initially visible as a child of hidden category 1.
158
        $category3 = core_course_category::create(array('name' => 'Cat3', 'visible' => 1, 'parent' => $category1->id));
159
        $this->assertEquals(0, $category3->visible);
160
        $this->assertEquals(1, $category3->visibleold);
161
 
162
        // Show category 1 and make sure that category 2 is hidden and category 3 is visible.
163
        $category1->show();
164
        $this->assertEquals(1, core_course_category::get($category1->id)->visible);
165
        $this->assertEquals(0, core_course_category::get($category2->id)->visible);
166
        $this->assertEquals(1, core_course_category::get($category3->id)->visible);
167
 
168
        // Create visible category 4.
169
        $category4 = core_course_category::create(array('name' => 'Cat4'));
170
        $this->assertEquals(1, $category4->visible);
171
        $this->assertEquals(1, $category4->visibleold);
172
 
173
        // Create visible category 5 as a child of visible category 4.
174
        $category5 = core_course_category::create(array('name' => 'Cat5', 'parent' => $category4->id));
175
        $this->assertEquals(1, $category5->visible);
176
        $this->assertEquals(1, $category5->visibleold);
177
 
178
        // Hide category 4 and make sure category 5 is hidden too.
179
        $category4->hide();
180
        $this->assertEquals(0, $category4->visible);
181
        $this->assertEquals(0, $category4->visibleold);
182
        $category5 = core_course_category::get($category5->id); // We have to re-read from DB.
183
        $this->assertEquals(0, $category5->visible);
184
        $this->assertEquals(1, $category5->visibleold);
185
 
186
        // Show category 4 and make sure category 5 is visible too.
187
        $category4->show();
188
        $this->assertEquals(1, $category4->visible);
189
        $this->assertEquals(1, $category4->visibleold);
190
        $category5 = core_course_category::get($category5->id); // We have to re-read from DB.
191
        $this->assertEquals(1, $category5->visible);
192
        $this->assertEquals(1, $category5->visibleold);
193
 
194
        // Move category 5 under hidden category 2 and make sure it became hidden.
195
        $category5->change_parent($category2->id);
196
        $this->assertEquals(0, $category5->visible);
197
        $this->assertEquals(1, $category5->visibleold);
198
 
199
        // Re-read object for category 5 from DB and check again.
200
        $category5 = core_course_category::get($category5->id);
201
        $this->assertEquals(0, $category5->visible);
202
        $this->assertEquals(1, $category5->visibleold);
203
 
204
        // Rricky one! Move hidden category 5 under visible category ("Top") and make sure it is still hidden-
205
        // WHY? Well, different people may expect different behaviour here. So better keep it hidden.
206
        $category5->change_parent(0);
207
        $this->assertEquals(0, $category5->visible);
208
        $this->assertEquals(1, $category5->visibleold);
209
    }
210
 
211
    public function test_hierarchy() {
212
        $this->assign_capability('moodle/category:viewhiddencategories');
213
        $this->assign_capability('moodle/category:manage');
214
 
215
        $category1 = core_course_category::create(array('name' => 'Cat1'));
216
        $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id));
217
        $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category1->id));
218
        $category4 = core_course_category::create(array('name' => 'Cat4', 'parent' => $category2->id));
219
 
220
        // Check function get_children().
221
        $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children()));
222
        // Check function get_parents().
223
        $this->assertEquals(array($category1->id, $category2->id), $category4->get_parents());
224
 
225
        // Can not move category to itself or to it's children.
226
        $this->assertFalse($category1->can_change_parent($category2->id));
227
        $this->assertFalse($category2->can_change_parent($category2->id));
228
        // Can move category to grandparent.
229
        $this->assertTrue($category4->can_change_parent($category1->id));
230
 
231
        try {
232
            $category2->change_parent($category4->id);
233
            $this->fail('Exception expected - can not move category');
234
        } catch (\moodle_exception $e) {
235
            $this->assertInstanceOf('moodle_exception', $e);
236
        }
237
 
238
        $category4->change_parent(0);
239
        $this->assertEquals(array(), $category4->get_parents());
240
        $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children()));
241
        $this->assertEquals(array(), array_keys($category2->get_children()));
242
    }
243
 
244
    public function test_update() {
245
        $category1 = core_course_category::create(array('name' => 'Cat1'));
246
        $timecreated = $category1->timemodified;
247
        $this->assertSame('Cat1', $category1->name);
248
        $this->assertTrue(empty($category1->description));
249
        $this->waitForSecond();
250
        $testdescription = 'This is cat 1 а также русский текст';
251
        $category1->update(array('description' => $testdescription));
252
        $this->assertSame($testdescription, $category1->description);
253
        $category1 = core_course_category::get($category1->id);
254
        $this->assertSame($testdescription, $category1->description);
255
        \cache_helper::purge_by_event('changesincoursecat');
256
        $category1 = core_course_category::get($category1->id);
257
        $this->assertSame($testdescription, $category1->description);
258
 
259
        $this->assertGreaterThan($timecreated, $category1->timemodified);
260
    }
261
 
262
    public function test_delete() {
263
        global $DB;
264
 
265
        $this->assign_capability('moodle/category:manage');
266
        $this->assign_capability('moodle/course:create');
267
 
268
        $initialcatid = $DB->get_field_sql('SELECT max(id) from {course_categories}');
269
 
270
        $category1 = core_course_category::create(array('name' => 'Cat1'));
271
        $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id));
272
        $category3 = core_course_category::create(array('name' => 'Cat3'));
273
        $category4 = core_course_category::create(array('name' => 'Cat4', 'parent' => $category2->id));
274
 
275
        $course1 = $this->getDataGenerator()->create_course(array('category' => $category2->id));
276
        $course2 = $this->getDataGenerator()->create_course(array('category' => $category4->id));
277
        $course3 = $this->getDataGenerator()->create_course(array('category' => $category4->id));
278
        $course4 = $this->getDataGenerator()->create_course(array('category' => $category1->id));
279
 
280
        // Now we have
281
        // $category1
282
        //   $category2
283
        //      $category4
284
        //        $course2
285
        //        $course3
286
        //      $course1
287
        //   $course4
288
        // $category3
289
        // structure.
290
 
291
        // Login as another user to test course:delete capability (user who created course can delete it within 24h even without cap).
292
        $this->setUser($this->getDataGenerator()->create_user());
293
 
294
        // Delete category 2 and move content to category 3.
295
        $this->assertFalse($category2->can_move_content_to($category3->id)); // No luck!
296
        // Add necessary capabilities.
297
        $this->assign_capability('moodle/course:create', CAP_ALLOW, \context_coursecat::instance($category3->id));
298
        $this->assign_capability('moodle/category:manage');
299
        $this->assertTrue($category2->can_move_content_to($category3->id)); // Hurray!
300
        $category2->delete_move($category3->id);
301
 
302
        // Make sure we have:
303
        // $category1
304
        //   $course4
305
        // $category3
306
        //    $category4
307
        //      $course2
308
        //      $course3
309
        //    $course1
310
        // structure.
311
 
312
        $this->assertNull(core_course_category::get($category2->id, IGNORE_MISSING, true));
313
        $this->assertEquals(array(), $category1->get_children());
314
        $this->assertEquals(array($category4->id), array_keys($category3->get_children()));
315
        $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course2->id)));
316
        $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course3->id)));
317
        $this->assertEquals($category3->id, $DB->get_field('course', 'category', array('id' => $course1->id)));
318
 
319
        // Delete category 3 completely.
320
        $this->assertFalse($category3->can_delete_full()); // No luck!
321
        // Add necessary capabilities.
322
        $this->assign_capability('moodle/course:delete', CAP_ALLOW, \context_coursecat::instance($category3->id));
323
        $this->assertTrue($category3->can_delete_full()); // Hurray!
324
        $category3->delete_full();
325
 
326
        // Make sure we have:
327
        // $category1
328
        //   $course4
329
        // structure.
330
 
331
        // Note that we also have default course category and default 'site' course.
332
        $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course_categories} WHERE id > ?', array($initialcatid)));
333
        $this->assertEquals($category1->id, $DB->get_field_sql('SELECT max(id) FROM {course_categories}'));
334
        $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course} WHERE id <> ?', array(SITEID)));
335
        $this->assertEquals(array('id' => $course4->id, 'category' => $category1->id),
336
                (array)$DB->get_record_sql('SELECT id, category from {course} where id <> ?', array(SITEID)));
337
    }
338
 
339
    public function test_get_children() {
340
        $category1 = core_course_category::create(array('name' => 'Cat1'));
341
        $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id));
342
        $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category1->id, 'visible' => 0));
343
        $category4 = core_course_category::create(array('name' => 'Cat4', 'idnumber' => '12', 'parent' => $category1->id));
344
        $category5 = core_course_category::create(array('name' => 'Cat5', 'idnumber' => '11',
345
            'parent' => $category1->id, 'visible' => 0));
346
        $category6 = core_course_category::create(array('name' => 'Cat6', 'idnumber' => '10', 'parent' => $category1->id));
347
        $category7 = core_course_category::create(array('name' => 'Cat0', 'parent' => $category1->id));
348
 
349
        $children = $category1->get_children();
350
        // User does not have the capability to view hidden categories, so the list should be
351
        // 2, 4, 6, 7.
352
        $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children));
353
        $this->assertEquals(4, $category1->get_children_count());
354
 
355
        $children = $category1->get_children(array('offset' => 2));
356
        $this->assertEquals(array($category6->id, $category7->id), array_keys($children));
357
        $this->assertEquals(4, $category1->get_children_count());
358
 
359
        $children = $category1->get_children(array('limit' => 2));
360
        $this->assertEquals(array($category2->id, $category4->id), array_keys($children));
361
 
362
        $children = $category1->get_children(array('offset' => 1, 'limit' => 2));
363
        $this->assertEquals(array($category4->id, $category6->id), array_keys($children));
364
 
365
        $children = $category1->get_children(array('sort' => array('name' => 1)));
366
        // Must be 7, 2, 4, 6.
367
        $this->assertEquals(array($category7->id, $category2->id, $category4->id, $category6->id), array_keys($children));
368
 
369
        $children = $category1->get_children(array('sort' => array('idnumber' => 1, 'name' => -1)));
370
        // Must be 2, 7, 6, 4.
371
        $this->assertEquals(array($category2->id, $category7->id, $category6->id, $category4->id), array_keys($children));
372
 
373
        // Check that everything is all right after purging the caches.
374
        \cache_helper::purge_by_event('changesincoursecat');
375
        $children = $category1->get_children();
376
        $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children));
377
        $this->assertEquals(4, $category1->get_children_count());
378
    }
379
 
380
    /**
381
     * Test the get_all_children_ids function.
382
     */
383
    public function test_get_all_children_ids() {
384
        $category1 = core_course_category::create(array('name' => 'Cat1'));
385
        $category2 = core_course_category::create(array('name' => 'Cat2'));
386
        $category11 = core_course_category::create(array('name' => 'Cat11', 'parent' => $category1->id));
387
        $category12 = core_course_category::create(array('name' => 'Cat12', 'parent' => $category1->id));
388
        $category13 = core_course_category::create(array('name' => 'Cat13', 'parent' => $category1->id));
389
        $category111 = core_course_category::create(array('name' => 'Cat111', 'parent' => $category11->id));
390
        $category112 = core_course_category::create(array('name' => 'Cat112', 'parent' => $category11->id));
391
        $category1121 = core_course_category::create(array('name' => 'Cat1121', 'parent' => $category112->id));
392
 
393
        $this->assertCount(0, $category2->get_all_children_ids());
394
        $this->assertCount(6, $category1->get_all_children_ids());
395
 
396
        $cmpchildrencat1 = array($category11->id, $category12->id, $category13->id, $category111->id, $category112->id,
397
                $category1121->id);
398
        $childrencat1 = $category1->get_all_children_ids();
399
        // Order of values does not matter. Compare sorted arrays.
400
        sort($cmpchildrencat1);
401
        sort($childrencat1);
402
        $this->assertEquals($cmpchildrencat1, $childrencat1);
403
 
404
        $this->assertCount(3, $category11->get_all_children_ids());
405
        $this->assertCount(0, $category111->get_all_children_ids());
406
        $this->assertCount(1, $category112->get_all_children_ids());
407
 
408
        $this->assertEquals(array($category1121->id), $category112->get_all_children_ids());
409
    }
410
 
411
    /**
412
     * Test the countall function
413
     */
414
    public function test_count_all() {
415
        global $DB;
416
        // Dont assume there is just one. An add-on might create a category as part of the install.
417
        $numcategories = $DB->count_records('course_categories');
418
        $this->assertEquals($numcategories, core_course_category::count_all());
419
        $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' .
420
            'core_course_category::is_simple_site()', DEBUG_DEVELOPER);
421
        $category1 = core_course_category::create(array('name' => 'Cat1'));
422
        $category2 = core_course_category::create(array('name' => 'Cat2', 'parent' => $category1->id));
423
        $category3 = core_course_category::create(array('name' => 'Cat3', 'parent' => $category2->id, 'visible' => 0));
424
        // Now we've got three more.
425
        $this->assertEquals($numcategories + 3, core_course_category::count_all());
426
        $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' .
427
            'core_course_category::is_simple_site()', DEBUG_DEVELOPER);
428
        \cache_helper::purge_by_event('changesincoursecat');
429
        // We should still have 4.
430
        $this->assertEquals($numcategories + 3, core_course_category::count_all());
431
        $this->assertDebuggingCalled('Method core_course_category::count_all() is deprecated. Please use ' .
432
            'core_course_category::is_simple_site()', DEBUG_DEVELOPER);
433
    }
434
 
435
    /**
436
     * Test the is_simple_site function
437
     */
438
    public function test_is_simple_site() {
439
        // By default site has one category and is considered simple.
440
        $this->assertEquals(true, core_course_category::is_simple_site());
441
        $default = core_course_category::get_default();
442
        // When there is only one category but it is hidden, it is not a simple site.
443
        $default->update(['visible' => 0]);
444
        $this->assertEquals(false, core_course_category::is_simple_site());
445
        $default->update(['visible' => 1]);
446
        $this->assertEquals(true, core_course_category::is_simple_site());
447
        // As soon as there is more than one category, site is not simple any more.
448
        core_course_category::create(array('name' => 'Cat1'));
449
        $this->assertEquals(false, core_course_category::is_simple_site());
450
    }
451
 
452
    /**
453
     * Test a categories ability to resort courses.
454
     */
455
    public function test_resort_courses() {
456
        $this->resetAfterTest(true);
457
        $generator = $this->getDataGenerator();
458
        $category = $generator->create_category();
459
        $course1 = $generator->create_course(array(
460
            'category' => $category->id,
461
            'idnumber' => '006-01',
462
            'shortname' => 'Biome Study',
463
            'fullname' => '<span lang="ar" class="multilang">'.'دراسة منطقة إحيائية'.'</span><span lang="en" class="multilang">Biome Study</span>',
464
            'timecreated' => '1000000001'
465
        ));
466
        $course2 = $generator->create_course(array(
467
            'category' => $category->id,
468
            'idnumber' => '007-02',
469
            'shortname' => 'Chemistry Revision',
470
            'fullname' => 'Chemistry Revision',
471
            'timecreated' => '1000000002'
472
        ));
473
        $course3 = $generator->create_course(array(
474
            'category' => $category->id,
475
            'idnumber' => '007-03',
476
            'shortname' => 'Swiss Rolls and Sunflowers',
477
            'fullname' => 'Aarkvarks guide to Swiss Rolls and Sunflowers',
478
            'timecreated' => '1000000003'
479
        ));
480
        $course4 = $generator->create_course(array(
481
            'category' => $category->id,
482
            'idnumber' => '006-04',
483
            'shortname' => 'Scratch',
484
            'fullname' => '<a href="test.php">Basic Scratch</a>',
485
            'timecreated' => '1000000004'
486
        ));
487
        $c1 = (int)$course1->id;
488
        $c2 = (int)$course2->id;
489
        $c3 = (int)$course3->id;
490
        $c4 = (int)$course4->id;
491
 
492
        $coursecat = core_course_category::get($category->id);
493
        $this->assertTrue($coursecat->resort_courses('idnumber'));
494
        $this->assertSame(array($c1, $c4, $c2, $c3), array_keys($coursecat->get_courses()));
495
 
496
        $this->assertTrue($coursecat->resort_courses('shortname'));
497
        $this->assertSame(array($c1, $c2, $c4, $c3), array_keys($coursecat->get_courses()));
498
 
499
        $this->assertTrue($coursecat->resort_courses('timecreated'));
500
        $this->assertSame(array($c1, $c2, $c3, $c4), array_keys($coursecat->get_courses()));
501
 
502
        try {
503
            // Enable the multilang filter and set it to apply to headings and content.
504
            \filter_manager::reset_caches();
505
            filter_set_global_state('multilang', TEXTFILTER_ON);
506
            filter_set_applies_to_strings('multilang', true);
507
            $expected = array($c3, $c4, $c1, $c2);
508
        } catch (\coding_exception $ex) {
509
            $expected = array($c3, $c4, $c2, $c1);
510
        }
511
        $this->assertTrue($coursecat->resort_courses('fullname'));
512
        $this->assertSame($expected, array_keys($coursecat->get_courses()));
513
    }
514
 
515
    public function test_get_search_courses() {
516
        global $DB;
517
 
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
        $user = $this->getDataGenerator()->create_user();
584
        $this->setUser($user);
585
 
586
        // Add necessary capabilities.
587
        $this->assign_capability('moodle/course:create', CAP_ALLOW, \context_coursecat::instance($cat2->id));
588
        // Do another search with restricted capabilities.
589
        $reqcaps = array('moodle/course:create');
590
        $res = core_course_category::search_courses(array('search' => 'test'), array(), $reqcaps);
591
        $this->assertEquals(array($c8->id, $c5->id), array_keys($res));
592
        $this->assertEquals(2, core_course_category::search_courses_count(array('search' => 'test'), array(), $reqcaps));
593
 
594
        // We should get no courses here as user is not enrolled to any courses.
595
        $res = core_course_category::search_courses([
596
            'search' => '',
597
            'limittoenrolled' => 1,
598
        ]);
599
        $this->assertEquals([], $res);
600
        $this->assertEquals(0, core_course_category::search_courses_count([
601
            'search' => '',
602
            'limittoenrolled' => 1,
603
        ]));
604
 
605
        $manual = enrol_get_plugin('manual');
606
        $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
607
        $enrol = $DB->get_record('enrol', ['courseid' => $c5->id, 'enrol' => 'manual'], '*', MUST_EXIST);
608
        $manual->enrol_user($enrol, $user->id, $teacherrole->id);
609
 
610
        // Avoid using the cached values from previous method call.
611
        \cache::make('core', 'coursecat')->purge();
612
 
613
        // As the user is now enrolled, we should get this one course.
614
        $res = core_course_category::search_courses([
615
            'search' => '',
616
            'limittoenrolled' => 1,
617
        ]);
618
        $this->assertEquals([$c5->id], array_keys($res));
619
        $this->assertEquals(1, core_course_category::search_courses_count([
620
            'search' => '',
621
            'limittoenrolled' => 1,
622
        ]));
623
    }
624
 
625
    public function test_course_contacts() {
626
        global $DB, $CFG;
627
 
628
        set_config('coursecontactduplicates', false);
629
 
630
        $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'));
631
        $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
632
        $studentrole = $DB->get_record('role', array('shortname'=>'student'));
633
        $oldcoursecontact = $CFG->coursecontact;
634
 
635
        $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id;
636
 
637
        /*
638
         * User is listed in course contacts for the course if he has one of the
639
         * "course contact" roles ($CFG->coursecontact) AND is enrolled in the course.
640
         * If the user has several roles only the highest is displayed.
641
         */
642
 
643
        // Test case:
644
        //
645
        // == Cat1 (user2 has teacher role)
646
        //   == Cat2
647
        //     -- course21 (user2 is enrolled as manager) | [Expected] Manager: F2 L2
648
        //     -- course22 (user2 is enrolled as student) | [Expected] Teacher: F2 L2
649
        //     == Cat4 (user2 has manager role)
650
        //       -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | [Expected] Manager: F5 L5, Teacher: F4 L4
651
        //       -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2
652
        //   == Cat3 (user3 has manager role)
653
        //     -- course31 (user3 is enrolled as student) | [Expected] Manager: F3 L3
654
        //     -- course32                                | [Expected]
655
        //   -- course11 (user1 is enrolled as teacher)   | [Expected] Teacher: F1 L1
656
        //   -- course12 (user1 has teacher role)         | [Expected]
657
        //                also user4 is enrolled as teacher but enrolment is not active
658
        $category = $course = $enrol = $user = array();
659
        $category[1] = core_course_category::create(array('name' => 'Cat1'))->id;
660
        $category[2] = core_course_category::create(array('name' => 'Cat2', 'parent' => $category[1]))->id;
661
        $category[3] = core_course_category::create(array('name' => 'Cat3', 'parent' => $category[1]))->id;
662
        $category[4] = core_course_category::create(array('name' => 'Cat4', 'parent' => $category[2]))->id;
663
        foreach (array(1, 2, 3, 4) as $catid) {
664
            foreach (array(1, 2) as $courseid) {
665
                $course[$catid][$courseid] = $this->getDataGenerator()->create_course(array('idnumber' => 'id'.$catid.$courseid,
666
                    'category' => $category[$catid]))->id;
667
                $enrol[$catid][$courseid] = $DB->get_record('enrol', array('courseid'=>$course[$catid][$courseid], 'enrol'=>'manual'), '*', MUST_EXIST);
668
            }
669
        }
670
        foreach (array(1, 2, 3, 4, 5) as $userid) {
671
            $user[$userid] = $this->getDataGenerator()->create_user(array('firstname' => 'F'.$userid, 'lastname' => 'L'.$userid))->id;
672
        }
673
 
674
        $manual = enrol_get_plugin('manual');
675
 
676
        // Nobody is enrolled now and course contacts are empty.
677
        $allcourses = core_course_category::get(0)->get_courses(
678
            array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1)));
679
        foreach ($allcourses as $onecourse) {
680
            $this->assertEmpty($onecourse->get_course_contacts());
681
        }
682
 
683
        // Cat1 (user2 has teacher role)
684
        role_assign($teacherrole->id, $user[2], \context_coursecat::instance($category[1]));
685
        // course21 (user2 is enrolled as manager)
686
        $manual->enrol_user($enrol[2][1], $user[2], $managerrole->id);
687
        // course22 (user2 is enrolled as student)
688
        $manual->enrol_user($enrol[2][2], $user[2], $studentrole->id);
689
        // Cat4 (user2 has manager role)
690
        role_assign($managerrole->id, $user[2], \context_coursecat::instance($category[4]));
691
        // course41 (user4 is enrolled as teacher, user5 is enrolled as manager)
692
        $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id);
693
        $manual->enrol_user($enrol[4][1], $user[5], $managerrole->id);
694
        // course42 (user2 is enrolled as teacher)
695
        $manual->enrol_user($enrol[4][2], $user[2], $teacherrole->id);
696
        // Cat3 (user3 has manager role)
697
        role_assign($managerrole->id, $user[3], \context_coursecat::instance($category[3]));
698
        // course31 (user3 is enrolled as student)
699
        $manual->enrol_user($enrol[3][1], $user[3], $studentrole->id);
700
        // course11 (user1 is enrolled as teacher)
701
        $manual->enrol_user($enrol[1][1], $user[1], $teacherrole->id);
702
        // -- course12 (user1 has teacher role)
703
        //                also user4 is enrolled as teacher but enrolment is not active
704
        role_assign($teacherrole->id, $user[1], \context_course::instance($course[1][2]));
705
        $manual->enrol_user($enrol[1][2], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
706
 
707
        $allcourses = core_course_category::get(0)->get_courses(
708
            array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1)));
709
        // Simplify the list of contacts for each course (similar as renderer would do).
710
        $contacts = array();
711
        foreach (array(1, 2, 3, 4) as $catid) {
712
            foreach (array(1, 2) as $courseid) {
713
                $tmp = array();
714
                foreach ($allcourses[$course[$catid][$courseid]]->get_course_contacts() as $contact) {
715
                    $tmp[] = $contact['rolename']. ': '. $contact['username'];
716
                }
717
                $contacts[$catid][$courseid] = join(', ', $tmp);
718
            }
719
        }
720
 
721
        // Assert:
722
        //     -- course21 (user2 is enrolled as manager) | Manager: F2 L2
723
        $this->assertSame('Manager: F2 L2', $contacts[2][1]);
724
        //     -- course22 (user2 is enrolled as student) | Teacher: F2 L2
725
        $this->assertSame('Teacher: F2 L2', $contacts[2][2]);
726
        //       -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | Manager: F5 L5, Teacher: F4 L4
727
        $this->assertSame('Manager: F5 L5, Teacher: F4 L4', $contacts[4][1]);
728
        //       -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2
729
        $this->assertSame('Manager: F2 L2', $contacts[4][2]);
730
        //     -- course31 (user3 is enrolled as student) | Manager: F3 L3
731
        $this->assertSame('Manager: F3 L3', $contacts[3][1]);
732
        //     -- course32                                |
733
        $this->assertSame('', $contacts[3][2]);
734
        //   -- course11 (user1 is enrolled as teacher)   | Teacher: F1 L1
735
        $this->assertSame('Teacher: F1 L1', $contacts[1][1]);
736
        //   -- course12 (user1 has teacher role)         |
737
        $this->assertSame('', $contacts[1][2]);
738
 
739
        // Suspend user 4 and make sure he is no longer in contacts of course 1 in category 4.
740
        $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
741
        $allcourses = core_course_category::get(0)->get_courses(array(
742
                'recursive' => true,
743
                'coursecontacts' => true,
744
                'sort' => array('idnumber' => 1))
745
        );
746
        $contacts = $allcourses[$course[4][1]]->get_course_contacts();
747
        $this->assertCount(1, $contacts);
748
        $contact = reset($contacts);
749
        $this->assertEquals('F5 L5', $contact['username']);
750
 
751
        $CFG->coursecontact = $oldcoursecontact;
752
    }
753
 
754
    public function test_course_contacts_with_duplicates() {
755
        global $DB, $CFG;
756
 
757
        set_config('coursecontactduplicates', true);
758
 
759
        $displayall = get_config('core', 'coursecontactduplicates');
760
        $this->assertEquals(true, $displayall);
761
 
762
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
763
        $managerrole = $DB->get_record('role', array('shortname' => 'manager'));
764
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
765
        $oldcoursecontact = $CFG->coursecontact;
766
 
767
        $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id;
768
 
769
        /*
770
        * User is listed in course contacts for the course if he has one of the
771
        * "course contact" roles ($CFG->coursecontact) AND is enrolled in the course.
772
        * If the user has several roles all roles are displayed, but each role only once per user.
773
        */
774
 
775
        /*
776
        * Test case:
777
        *
778
        * == Cat1 (user2 has teacher role)
779
        *    == Cat2
780
        *      -- course21 (user2 is enrolled as manager) | [Expected] Manager: F2 L2
781
        *      -- course22 (user2 is enrolled as student) | [Expected] Teacher: F2 L2
782
        *      == Cat4 (user2 has manager role)
783
        *        -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager)
784
        *                                                 | [Expected] Manager: F5 L5, Teacher: F4 L4
785
        *        -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2
786
        *    == Cat3 (user3 has manager role)
787
        *      -- course31 (user3 is enrolled as student) | [Expected] Manager: F3 L3
788
        *      -- course32                                | [Expected]
789
        *    -- course11 (user1 is enrolled as teacher)   | [Expected] Teacher: F1 L1
790
        *    -- course12 (user1 has teacher role)         | [Expected]
791
        *                 also user4 is enrolled as teacher but enrolment is not active
792
        */
793
        $category = $course = $enrol = $user = array();
794
        $category[1] = core_course_category::create(array('name' => 'Cat1'))->id;
795
        $category[2] = core_course_category::create(array('name' => 'Cat2', 'parent' => $category[1]))->id;
796
        $category[3] = core_course_category::create(array('name' => 'Cat3', 'parent' => $category[1]))->id;
797
        $category[4] = core_course_category::create(array('name' => 'Cat4', 'parent' => $category[2]))->id;
798
        foreach (array(1, 2, 3, 4) as $catid) {
799
            foreach (array(1, 2) as $courseid) {
800
                $course[$catid][$courseid] = $this->getDataGenerator()->create_course(array(
801
                        'idnumber' => 'id'.$catid.$courseid,
802
                        'category' => $category[$catid])
803
                )->id;
804
                $enrol[$catid][$courseid] = $DB->get_record(
805
                        'enrol',
806
                        array('courseid' => $course[$catid][$courseid], 'enrol' => 'manual'),
807
                        '*',
808
                        MUST_EXIST
809
                );
810
            }
811
        }
812
        foreach (array(1, 2, 3, 4, 5) as $userid) {
813
            $user[$userid] = $this->getDataGenerator()->create_user(array(
814
                            'firstname' => 'F'.$userid,
815
                            'lastname' => 'L'.$userid)
816
            )->id;
817
        }
818
 
819
        $manual = enrol_get_plugin('manual');
820
 
821
        // Nobody is enrolled now and course contacts are empty.
822
        $allcourses = core_course_category::get(0)->get_courses(array(
823
                'recursive' => true,
824
                'coursecontacts' => true,
825
                'sort' => array('idnumber' => 1))
826
        );
827
        foreach ($allcourses as $onecourse) {
828
            $this->assertEmpty($onecourse->get_course_contacts());
829
        }
830
 
831
        // Cat1: user2 has teacher role.
832
        role_assign($teacherrole->id, $user[2], \context_coursecat::instance($category[1]));
833
        // Course21: user2 is enrolled as manager.
834
        $manual->enrol_user($enrol[2][1], $user[2], $managerrole->id);
835
        // Course22: user2 is enrolled as student.
836
        $manual->enrol_user($enrol[2][2], $user[2], $studentrole->id);
837
        // Cat4: user2 has manager role.
838
        role_assign($managerrole->id, $user[2], \context_coursecat::instance($category[4]));
839
        // Course41: user4 is enrolled as teacher, user5 is enrolled as manager.
840
        $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id);
841
        $manual->enrol_user($enrol[4][1], $user[5], $managerrole->id);
842
        // Course42: user2 is enrolled as teacher.
843
        $manual->enrol_user($enrol[4][2], $user[2], $teacherrole->id);
844
        // Cat3: user3 has manager role.
845
        role_assign($managerrole->id, $user[3], \context_coursecat::instance($category[3]));
846
        // Course31: user3 is enrolled as student.
847
        $manual->enrol_user($enrol[3][1], $user[3], $studentrole->id);
848
        // Course11: user1 is enrolled as teacher and user4 is enrolled as teacher and has manager role.
849
        $manual->enrol_user($enrol[1][1], $user[1], $teacherrole->id);
850
        $manual->enrol_user($enrol[1][1], $user[4], $teacherrole->id);
851
        role_assign($managerrole->id, $user[4], \context_course::instance($course[1][1]));
852
        // Course12: user1 has teacher role, but is not enrolled, as well as user4 is enrolled as teacher, but user4's enrolment is
853
        // not active.
854
        role_assign($teacherrole->id, $user[1], \context_course::instance($course[1][2]));
855
        $manual->enrol_user($enrol[1][2], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
856
 
857
        $allcourses = core_course_category::get(0)->get_courses(
858
                array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1)));
859
        // Simplify the list of contacts for each course (similar as renderer would do).
860
        $contacts = array();
861
        foreach (array(1, 2, 3, 4) as $catid) {
862
            foreach (array(1, 2) as $courseid) {
863
                $tmp = array();
864
                foreach ($allcourses[$course[$catid][$courseid]]->get_course_contacts() as $contact) {
865
                    $rolenames = array_map(function ($role) {
866
                        return $role->displayname;
867
                    }, $contact['roles']);
868
                    $tmp[] = implode(", ", $rolenames). ': '.
869
                            $contact['username'];
870
                }
871
                $contacts[$catid][$courseid] = join(', ', $tmp);
872
            }
873
        }
874
 
875
        // Assert:
876
        // Course21: user2 is enrolled as manager. [Expected] Manager: F2 L2, Teacher: F2 L2.
877
        $this->assertSame('Manager, Teacher: F2 L2', $contacts[2][1]);
878
        // Course22: user2 is enrolled as student. [Expected] Teacher: F2 L2.
879
        $this->assertSame('Teacher: F2 L2', $contacts[2][2]);
880
        // Course41: user4 is enrolled as teacher, user5 is enrolled as manager. [Expected] Manager: F5 L5, Teacher: F4 L4.
881
        $this->assertSame('Manager: F5 L5, Teacher: F4 L4', $contacts[4][1]);
882
        // Course42: user2 is enrolled as teacher. [Expected] Manager: F2 L2, Teacher: F2 L2.
883
        $this->assertSame('Manager, Teacher: F2 L2', $contacts[4][2]);
884
        // Course31: user3 is enrolled as student. [Expected] Manager: F3 L3.
885
        $this->assertSame('Manager: F3 L3', $contacts[3][1]);
886
        // Course32: nobody is enrolled. [Expected] (nothing).
887
        $this->assertSame('', $contacts[3][2]);
888
        // Course11: user1 is enrolled as teacher and user4 is enrolled as teacher and has manager role. [Expected] Manager: F4 L4,
889
        // Teacher: F1 L1, Teacher: F4 L4.
890
        $this->assertSame('Manager, Teacher: F4 L4, Teacher: F1 L1', $contacts[1][1]);
891
        // Course12: user1 has teacher role, but is not enrolled, as well as user4 is enrolled as teacher, but user4's enrolment is
892
        // not active. [Expected] (nothing).
893
        $this->assertSame('', $contacts[1][2]);
894
 
895
        // Suspend user 4 and make sure he is no longer in contacts of course 1 in category 4.
896
        $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
897
        $allcourses = core_course_category::get(0)->get_courses(array(
898
                'recursive' => true,
899
                'coursecontacts' => true,
900
                'sort' => array('idnumber' => 1)
901
        ));
902
        $contacts = $allcourses[$course[4][1]]->get_course_contacts();
903
        $this->assertCount(1, $contacts);
904
        $contact = reset($contacts);
905
        $this->assertEquals('F5 L5', $contact['username']);
906
 
907
        $CFG->coursecontact = $oldcoursecontact;
908
    }
909
 
910
    public function test_overview_files() {
911
        global $CFG;
912
        $this->setAdminUser();
913
        $cat1 = core_course_category::create(array('name' => 'Cat1'));
914
 
915
        // Create course c1 with one image file.
916
        $dratid1 = $this->fill_draft_area(array('filename.jpg' => 'Test file contents1'));
917
        $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
918
            'fullname' => 'Test 1', 'overviewfiles_filemanager' => $dratid1));
919
        // Create course c2 with two image files (only one file will be added because of settings).
920
        $dratid2 = $this->fill_draft_area(array('filename21.jpg' => 'Test file contents21', 'filename22.jpg' => 'Test file contents22'));
921
        $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
922
            'fullname' => 'Test 2', 'overviewfiles_filemanager' => $dratid2));
923
        // Create course c3 without files.
924
        $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3'));
925
 
926
        // Change the settings to allow multiple files of any types.
927
        $CFG->courseoverviewfileslimit = 3;
928
        $CFG->courseoverviewfilesext = '*';
929
        // Create course c5 with two image files.
930
        $dratid4 = $this->fill_draft_area(array('filename41.jpg' => 'Test file contents41', 'filename42.jpg' => 'Test file contents42'));
931
        $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
932
            'fullname' => 'Test 4', 'overviewfiles_filemanager' => $dratid4));
933
        // Create course c6 with non-image file.
934
        $dratid5 = $this->fill_draft_area(array('filename51.zip' => 'Test file contents51'));
935
        $c5 = $this->getDataGenerator()->create_course(array('category' => $cat1->id,
936
            'fullname' => 'Test 5', 'overviewfiles_filemanager' => $dratid5));
937
 
938
        // Reset default settings.
939
        $CFG->courseoverviewfileslimit = 1;
940
        $CFG->courseoverviewfilesext = 'web_image';
941
 
942
        $courses = $cat1->get_courses();
943
        $this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
944
        $this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
945
        $this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
946
        $this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
947
        $this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Does not validate the filetypes.
948
 
949
        $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
950
        $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles()));
951
        $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
952
        $this->assertEquals(1, count($courses[$c4->id]->get_course_overviewfiles()));
953
        $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles())); // Validate the filetypes.
954
 
955
        // Overview files are not allowed, all functions return empty values.
956
        $CFG->courseoverviewfileslimit = 0;
957
 
958
        $this->assertFalse($courses[$c1->id]->has_course_overviewfiles());
959
        $this->assertFalse($courses[$c2->id]->has_course_overviewfiles());
960
        $this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
961
        $this->assertFalse($courses[$c4->id]->has_course_overviewfiles());
962
        $this->assertFalse($courses[$c5->id]->has_course_overviewfiles());
963
 
964
        $this->assertEquals(0, count($courses[$c1->id]->get_course_overviewfiles()));
965
        $this->assertEquals(0, count($courses[$c2->id]->get_course_overviewfiles()));
966
        $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
967
        $this->assertEquals(0, count($courses[$c4->id]->get_course_overviewfiles()));
968
        $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles()));
969
 
970
        // Multiple overview files are allowed but still limited to images.
971
        $CFG->courseoverviewfileslimit = 3;
972
 
973
        $this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
974
        $this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
975
        $this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
976
        $this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
977
        $this->assertTrue($courses[$c5->id]->has_course_overviewfiles()); // Still does not validate the filetypes.
978
 
979
        $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
980
        $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles())); // Only 1 file was actually added.
981
        $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
982
        $this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles()));
983
        $this->assertEquals(0, count($courses[$c5->id]->get_course_overviewfiles()));
984
 
985
        // Multiple overview files of any type are allowed.
986
        $CFG->courseoverviewfilesext = '*';
987
 
988
        $this->assertTrue($courses[$c1->id]->has_course_overviewfiles());
989
        $this->assertTrue($courses[$c2->id]->has_course_overviewfiles());
990
        $this->assertFalse($courses[$c3->id]->has_course_overviewfiles());
991
        $this->assertTrue($courses[$c4->id]->has_course_overviewfiles());
992
        $this->assertTrue($courses[$c5->id]->has_course_overviewfiles());
993
 
994
        $this->assertEquals(1, count($courses[$c1->id]->get_course_overviewfiles()));
995
        $this->assertEquals(1, count($courses[$c2->id]->get_course_overviewfiles()));
996
        $this->assertEquals(0, count($courses[$c3->id]->get_course_overviewfiles()));
997
        $this->assertEquals(2, count($courses[$c4->id]->get_course_overviewfiles()));
998
        $this->assertEquals(1, count($courses[$c5->id]->get_course_overviewfiles()));
999
    }
1000
 
1001
    public function test_get_nested_name() {
1002
        $cat1name = 'Cat1';
1003
        $cat2name = 'Cat2';
1004
        $cat3name = 'Cat3';
1005
        $cat4name = 'Cat4';
1006
        $category1 = core_course_category::create(array('name' => $cat1name));
1007
        $category2 = core_course_category::create(array('name' => $cat2name, 'parent' => $category1->id));
1008
        $category3 = core_course_category::create(array('name' => $cat3name, 'parent' => $category2->id));
1009
        $category4 = core_course_category::create(array('name' => $cat4name, 'parent' => $category2->id));
1010
 
1011
        $this->assertEquals($cat1name, $category1->get_nested_name(false));
1012
        $this->assertEquals("{$cat1name} / {$cat2name}", $category2->get_nested_name(false));
1013
        $this->assertEquals("{$cat1name} / {$cat2name} / {$cat3name}", $category3->get_nested_name(false));
1014
        $this->assertEquals("{$cat1name} / {$cat2name} / {$cat4name}", $category4->get_nested_name(false));
1015
    }
1016
 
1017
    public function test_coursecat_is_uservisible() {
1018
        global $USER;
1019
 
1020
        // Create category 1 as visible.
1021
        $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1));
1022
        // Create category 2 as hidden.
1023
        $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0));
1024
 
1025
        $this->assertTrue($category1->is_uservisible());
1026
        $this->assertFalse($category2->is_uservisible());
1027
 
1028
        $this->assign_capability('moodle/category:viewhiddencategories');
1029
 
1030
        $this->assertTrue($category1->is_uservisible());
1031
        $this->assertTrue($category2->is_uservisible());
1032
 
1033
        // First, store current user's id, then login as another user.
1034
        $userid = $USER->id;
1035
        $this->setUser($this->getDataGenerator()->create_user());
1036
 
1037
        // User $user should still have the moodle/category:viewhiddencategories capability.
1038
        $this->assertTrue($category1->is_uservisible($userid));
1039
        $this->assertTrue($category2->is_uservisible($userid));
1040
 
1041
        $this->assign_capability('moodle/category:viewhiddencategories', CAP_INHERIT);
1042
 
1043
        $this->assertTrue($category1->is_uservisible());
1044
        $this->assertFalse($category2->is_uservisible());
1045
    }
1046
 
1047
    public function test_current_user_coursecat_get() {
1048
        $this->assign_capability('moodle/category:viewhiddencategories');
1049
 
1050
        // Create category 1 as visible.
1051
        $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1));
1052
        // Create category 2 as hidden.
1053
        $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0));
1054
 
1055
        $this->assertEquals($category1->id, core_course_category::get($category1->id)->id);
1056
        $this->assertEquals($category2->id, core_course_category::get($category2->id)->id);
1057
 
1058
        // Login as another user to test core_course_category::get.
1059
        $this->setUser($this->getDataGenerator()->create_user());
1060
        $this->assertEquals($category1->id, core_course_category::get($category1->id)->id);
1061
 
1062
        // Expecting to get an exception as this new user does not have the moodle/category:viewhiddencategories capability.
1063
        $this->expectException('moodle_exception');
1064
        $this->expectExceptionMessage(get_string('cannotviewcategory', 'error'));
1065
        core_course_category::get($category2->id);
1066
    }
1067
 
1068
    public function test_another_user_coursecat_get() {
1069
        global $USER;
1070
 
1071
        $this->assign_capability('moodle/category:viewhiddencategories');
1072
 
1073
        // Create category 1 as visible.
1074
        $category1 = core_course_category::create(array('name' => 'Cat1', 'visible' => 1));
1075
        // Create category 2 as hidden.
1076
        $category2 = core_course_category::create(array('name' => 'Cat2', 'visible' => 0));
1077
 
1078
        // First, store current user's object, then login as another user.
1079
        $user1 = $USER;
1080
        $user2 = $this->getDataGenerator()->create_user();
1081
        $this->setUser($user2);
1082
 
1083
        $this->assertEquals($category1->id, core_course_category::get($category1->id, MUST_EXIST, false, $user1)->id);
1084
        $this->assertEquals($category2->id, core_course_category::get($category2->id, MUST_EXIST, false, $user1)->id);
1085
 
1086
        $this->setUser($user1);
1087
 
1088
        $this->assertEquals($category1->id, core_course_category::get($category1->id, MUST_EXIST, false, $user2)->id);
1089
        $this->expectException('moodle_exception');
1090
        $this->expectExceptionMessage(get_string('cannotviewcategory', 'error'));
1091
        core_course_category::get($category2->id, MUST_EXIST, false, $user2);
1092
    }
1093
 
1094
    /**
1095
     * Creates a draft area for current user and fills it with fake files
1096
     *
1097
     * @param array $files array of files that need to be added to filearea, filename => filecontents
1098
     * @return int draftid for the filearea
1099
     */
1100
    protected function fill_draft_area(array $files) {
1101
        global $USER;
1102
        $usercontext = \context_user::instance($USER->id);
1103
        $draftid = file_get_unused_draft_itemid();
1104
        foreach ($files as $filename => $filecontents) {
1105
            // Add actual file there.
1106
            $filerecord = array('component' => 'user', 'filearea' => 'draft',
1107
                    'contextid' => $usercontext->id, 'itemid' => $draftid,
1108
                    'filename' => $filename, 'filepath' => '/');
1109
            $fs = get_file_storage();
1110
            $fs->create_file_from_string($filerecord, $filecontents);
1111
        }
1112
        return $draftid;
1113
    }
1114
 
1115
    /**
1116
     * This test ensures that is the list of courses in a category can be retrieved while a course is being deleted.
1117
     */
1118
    public function test_get_courses_during_delete() {
1119
        global $DB;
1120
        $category = self::getDataGenerator()->create_category();
1121
        $course = self::getDataGenerator()->create_course(['category' => $category->id]);
1122
        $othercourse = self::getDataGenerator()->create_course(['category' => $category->id]);
1123
        $coursecategory = core_course_category::get($category->id);
1124
        // Get a list of courses before deletion to populate the cache.
1125
        $originalcourses = $coursecategory->get_courses();
1126
        $this->assertCount(2, $originalcourses);
1127
        $this->assertArrayHasKey($course->id, $originalcourses);
1128
        $this->assertArrayHasKey($othercourse->id, $originalcourses);
1129
        // Simulate the course deletion process being part way though.
1130
        $DB->delete_records('course', ['id' => $course->id]);
1131
        // Get the list of courses while a deletion is in progress.
1132
        $courses = $coursecategory->get_courses();
1133
        $this->assertCount(1, $courses);
1134
        $this->assertArrayHasKey($othercourse->id, $courses);
1135
    }
1136
 
1137
    /**
1138
     * Test get_nearest_editable_subcategory() method.
1139
     *
1140
     * @covers \core_course_category::get_nearest_editable_subcategory
1141
     */
1142
    public function test_get_nearest_editable_subcategory(): void {
1143
        global $DB;
1144
 
1145
        $coursecreatorrole = $DB->get_record('role', ['shortname' => 'coursecreator']);
1146
        $managerrole = $DB->get_record('role', ['shortname' => 'manager']);
1147
 
1148
        // Create categories.
1149
        $category1 = core_course_category::create(['name' => 'Cat1']);
1150
        $category2 = core_course_category::create(['name' => 'Cat2']);
1151
        $category3 = core_course_category::create(['name' => 'Cat3']);
1152
        // Get the category contexts.
1153
        $category1context = $category1->get_context();
1154
        $category2context = $category2->get_context();
1155
        $category3context = $category3->get_context();
1156
        // Create user.
1157
        $user1 = $this->getDataGenerator()->create_user();
1158
        $user2 = $this->getDataGenerator()->create_user();
1159
        $user3 = $this->getDataGenerator()->create_user();
1160
        // Assign the user1 to 'Course creator' role for Cat1.
1161
        role_assign($coursecreatorrole->id, $user1->id, $category1context->id);
1162
        // Assign the user2 to 'Manager' role for Cat3.
1163
        role_assign($managerrole->id, $user2->id, $category3context->id);
1164
 
1165
        // Start scenario 1.
1166
        // user3 has no permission to create course or manage category.
1167
        $this->setUser($user3);
1168
        $coursecat = core_course_category::user_top();
1169
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create']));
1170
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create']));
1171
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['manage']));
1172
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/category:manage']));
1173
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create', 'manage']));
1174
        // End scenario 1.
1175
 
1176
        // Start scenario 2.
1177
        // user1 has permission to create course but has no permission to manage category.
1178
        $this->setUser($user1);
1179
        $coursecat = core_course_category::user_top();
1180
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create']));
1181
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create']));
1182
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['manage']));
1183
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/category:manage']));
1184
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create', 'manage']));
1185
        // The get_nearest_editable_subcategory should return Cat1.
1186
        $this->assertEquals($category1->id, core_course_category::get_nearest_editable_subcategory($coursecat, ['create'])->id);
1187
        $this->assertEquals($category1->id,
1188
            core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create'])->id);
1189
        // Assign the user1 to 'Course creator' role for Cat2.
1190
        role_assign($coursecreatorrole->id, $user1->id, $category2context->id);
1191
        // The get_nearest_editable_subcategory should still return Cat1 (First creatable subcategory) for create course capability.
1192
        $this->assertEquals($category1->id, core_course_category::get_nearest_editable_subcategory($coursecat, ['create'])->id);
1193
        $this->assertEquals($category1->id,
1194
            core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create'])->id);
1195
        // End scenario 2.
1196
 
1197
        // Start scenario 3.
1198
        // user2 has no permission to create course but has permission to manage category.
1199
        $this->setUser($user2);
1200
        // Remove the moodle/course:create capability for the manager role.
1201
        unassign_capability('moodle/course:create', $managerrole->id);
1202
        $coursecat = core_course_category::user_top();
1203
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create']));
1204
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create']));
1205
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['manage']));
1206
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/category:manage']));
1207
        $this->assertEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create', 'manage']));
1208
        // The get_nearest_editable_subcategory should return Cat3.
1209
        $this->assertEquals($category3->id, core_course_category::get_nearest_editable_subcategory($coursecat, ['manage'])->id);
1210
        $this->assertEquals($category3->id,
1211
            core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/category:manage'])->id);
1212
        // End scenario 3.
1213
 
1214
        // Start scenario 4.
1215
        // user2 has both permission to create course and manage category.
1216
        // Add the moodle/course:create capability back again for the manager role.
1217
        assign_capability('moodle/course:create', CAP_ALLOW, $managerrole->id, $category3context->id);
1218
        $this->setUser($user2);
1219
        $coursecat = core_course_category::user_top();
1220
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create']));
1221
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/course:create']));
1222
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['manage']));
1223
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['moodle/category:manage']));
1224
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, ['create', 'manage']));
1225
        // The get_nearest_editable_subcategory should return Cat3.
1226
        $this->assertEquals($category3->id,
1227
            core_course_category::get_nearest_editable_subcategory($coursecat, ['create', 'manage'])->id);
1228
        $this->assertEquals($category3->id, core_course_category::get_nearest_editable_subcategory($coursecat,
1229
            ['moodle/course:create', 'moodle/category:manage'])->id);
1230
        // End scenario 4.
1231
 
1232
        // Start scenario 5.
1233
        // Exception will be thrown if $permissionstocheck is empty.
1234
        $this->setUser($user1);
1235
        $coursecat = core_course_category::user_top();
1236
        $this->expectException('coding_exception');
1237
        $this->expectExceptionMessage('Invalid permissionstocheck parameter');
1238
        $this->assertNotEmpty(core_course_category::get_nearest_editable_subcategory($coursecat, []));
1239
        // End scenario 5.
1240
    }
1241
 
1242
    /**
1243
     * Test get_nearest_editable_subcategory() method with hidden categories.
1244
     *
1245
     * @param int $visible  Whether the category is visible or not.
1246
     * @param bool $child   Whether the category is child of main category or not.
1247
     * @param string $role  The role the user must have.
1248
     * @param array $permissions An array of permissions we must check.
1249
     * @param bool $result Whether the result should be the category or null.
1250
     *
1251
     * @dataProvider get_nearest_editable_subcategory_provider
1252
     * @covers \core_course_category::get_nearest_editable_subcategory
1253
     */
1254
    public function test_get_nearest_editable_subcategory_with_hidden_categories(
1255
        int $visible = 0,
1256
        bool $child = false,
1257
        string $role = 'manager',
1258
        array $permissions = [],
1259
        bool $result = false
1260
    ): void {
1261
        global $DB;
1262
 
1263
        $userrole = $DB->get_record('role', ['shortname' => $role]);
1264
        $maincat = core_course_category::create(['name' => 'Main cat']);
1265
 
1266
        $catparams = new \stdClass();
1267
        $catparams->name = 'Test category';
1268
        $catparams->visible = $visible;
1269
        if ($child) {
1270
            $catparams->parent = $maincat->id;
1271
        }
1272
        $category = core_course_category::create($catparams);
1273
        $catcontext = $category->get_context();
1274
        $user = $this->getDataGenerator()->create_user();
1275
        role_assign($userrole->id, $user->id, $catcontext->id);
1276
        $this->setUser($user);
1277
 
1278
        $nearestcat = core_course_category::get_nearest_editable_subcategory(core_course_category::user_top(), $permissions);
1279
 
1280
        if ($result) {
1281
            $this->assertEquals($category->id, $nearestcat->id);
1282
        } else {
1283
            $this->assertEmpty($nearestcat);
1284
        }
1285
    }
1286
 
1287
    /**
1288
     * Data provider for test_get_nearest_editable_subcategory_with_hidden_categories().
1289
     *
1290
     * @return array
1291
     */
1292
    public function get_nearest_editable_subcategory_provider(): array {
1293
        return [
1294
            'Hidden main category for manager. Checking create and manage' => [
1295
                0,
1296
                false,
1297
                'manager',
1298
                ['create', 'manage'],
1299
                true,
1300
            ],
1301
            'Hidden main category for course creator. Checking create and manage' => [
1302
                0,
1303
                false,
1304
                'coursecreator',
1305
                ['create', 'manage'],
1306
                false,
1307
            ],
1308
            'Hidden main category for student. Checking create and manage' => [
1309
                0,
1310
                false,
1311
                'student',
1312
                ['create', 'manage'],
1313
                false,
1314
            ],
1315
            'Hidden main category for manager. Checking create' => [
1316
                0,
1317
                false,
1318
                'manager',
1319
                ['create'],
1320
                true,
1321
            ],
1322
            'Hidden main category for course creator. Checking create' => [
1323
                0,
1324
                false,
1325
                'coursecreator',
1326
                ['create'],
1327
                true,
1328
            ],
1329
            'Hidden main category for student. Checking create' => [
1330
                0,
1331
                false,
1332
                'student',
1333
                ['create'],
1334
                false,
1335
            ],
1336
            'Hidden subcategory for manager. Checking create and manage' => [
1337
                0,
1338
                true,
1339
                'manager',
1340
                ['create', 'manage'],
1341
                true,
1342
            ],
1343
            'Hidden subcategory for course creator. Checking create and manage' => [
1344
                0,
1345
                true,
1346
                'coursecreator',
1347
                ['create', 'manage'],
1348
                false,
1349
            ],
1350
            'Hidden subcategory for student. Checking create and manage' => [
1351
                0,
1352
                true,
1353
                'student',
1354
                ['create', 'manage'],
1355
                false,
1356
            ],
1357
            'Hidden subcategory for manager. Checking create' => [
1358
                0,
1359
                true,
1360
                'manager',
1361
                ['create'],
1362
                true,
1363
            ],
1364
            'Hidden subcategory for course creator. Checking create' => [
1365
                0,
1366
                true,
1367
                'coursecreator',
1368
                ['create'],
1369
                true,
1370
            ],
1371
            'Hidden subcategory for student. Checking create' => [
1372
                0,
1373
                true,
1374
                'student',
1375
                ['create'],
1376
                false,
1377
            ],
1378
        ];
1379
    }
1380
 
1381
    /**
1382
     * This test ensures that the filter context list is populated by the correct filter contexts from make_category_list.
1383
     *
1384
     * @coversNothing
1385
     */
1386
    public function test_make_category_list_context() {
1387
        global $DB;
1388
        // Ensure that the category list is empty.
1389
        $DB->delete_records('course_categories');
1390
        set_config('perfdebug', 15);
1391
 
1392
        // Create a few categories to populate the context cache.
1393
        $this->getDataGenerator()->create_category(['name' => 'cat1']);
1394
        $this->getDataGenerator()->create_category(['name' => 'cat2']);
1395
        $this->getDataGenerator()->create_category(['name' => 'cat3']);
1396
        $filtermanager = \filter_manager::instance();
1397
 
1398
        // Configure a filter to apply to all content and headings.
1399
        filter_set_global_state('multilang', TEXTFILTER_ON);
1400
        filter_set_applies_to_strings('multilang', true);
1401
 
1402
        $perf = $filtermanager->get_performance_summary();
1403
        $this->assertEquals(0, $perf[0]['contextswithfilters']);
1404
 
1405
        // Now fill the cache with the category strings.
1406
        \core_course_category::make_categories_list();
1407
        // 3 Categories + system context.
1408
        $perf = $filtermanager->get_performance_summary();
1409
        $this->assertEquals(3, $perf[0]['contextswithfilters']);
1410
        $filtermanager->reset_caches();
1411
        // We need to refresh the instance, resetting caches unloads the singleton.
1412
        $filtermanager = \filter_manager::instance();
1413
        \cache_helper::purge_by_definition('core', 'coursecat');
1414
 
1415
        // Now flip the bit on the filter context.
1416
        set_config('filternavigationwithsystemcontext', 1);
1417
 
1418
        // Repeat the check. Only context should be system context.
1419
        \core_course_category::make_categories_list();
1420
        $perf = $filtermanager->get_performance_summary();
1421
        $this->assertEquals(1, $perf[0]['contextswithfilters']);
1422
    }
1423
}