be7c2880b7c58fd92fe63942fe9556beba11412d
[moodle.git] / lib / tests / coursecatlib_test.php
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/>.
17 /**
18  * Tests for class coursecat from lib/coursecatlib.php
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2013 Marina Glancy
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/coursecatlib.php');
31 /**
32  * Functional test for coursecatlib.php
33  */
34 class core_coursecatlib_testcase extends advanced_testcase {
36     protected $roles;
38     protected function setUp() {
39         parent::setUp();
40         $this->resetAfterTest();
41         $user = $this->getDataGenerator()->create_user();
42         $this->setUser($user);
43     }
45     protected function get_roleid($context = null) {
46         global $USER;
47         if ($context === null) {
48             $context = context_system::instance();
49         }
50         if (is_object($context)) {
51             $context = $context->id;
52         }
53         if (empty($this->roles)) {
54             $this->roles = array();
55         }
56         if (empty($this->roles[$USER->id])) {
57             $this->roles[$USER->id] = array();
58         }
59         if (empty($this->roles[$USER->id][$context])) {
60             $this->roles[$USER->id][$context] = create_role('Role for '.$USER->id.' in '.$context, 'role'.$USER->id.'-'.$context, '-');
61             role_assign($this->roles[$USER->id][$context], $USER->id, $context);
62         }
63         return $this->roles[$USER->id][$context];
64     }
66     protected function assign_capability($capability, $permission = CAP_ALLOW, $contextid = null) {
67         if ($contextid === null) {
68             $contextid = context_system::instance();
69         }
70         if (is_object($contextid)) {
71             $contextid = $contextid->id;
72         }
73         assign_capability($capability, $permission, $this->get_roleid($contextid), $contextid, true);
74         accesslib_clear_all_caches_for_unit_testing();
75     }
77     public function test_create_coursecat() {
78         // Create the category.
79         $data = new stdClass();
80         $data->name = 'aaa';
81         $data->description = 'aaa';
82         $data->idnumber = '';
84         $category1 = coursecat::create($data);
86         // Initially confirm that base data was inserted correctly.
87         $this->assertSame($data->name, $category1->name);
88         $this->assertSame($data->description, $category1->description);
89         $this->assertSame($data->idnumber, $category1->idnumber);
91         $this->assertGreaterThanOrEqual(1, $category1->sortorder);
93         // Create two more categories and test the sortorder worked correctly.
94         $data->name = 'ccc';
95         $category2 = coursecat::create($data);
97         $data->name = 'bbb';
98         $category3 = coursecat::create($data);
100         $this->assertGreaterThan($category1->sortorder, $category2->sortorder);
101         $this->assertGreaterThan($category2->sortorder, $category3->sortorder);
102     }
104     public function test_name_idnumber_exceptions() {
105         try {
106             coursecat::create(array('name' => ''));
107             $this->fail('Missing category name exception expected in coursecat::create');
108         } catch (moodle_exception $e) {
109             $this->assertInstanceOf('moodle_exception', $e);
110         }
111         $cat1 = coursecat::create(array('name' => 'Cat1', 'idnumber' => '1'));
112         try {
113             $cat1->update(array('name' => ''));
114             $this->fail('Missing category name exception expected in coursecat::update');
115         } catch (moodle_exception $e) {
116             $this->assertInstanceOf('moodle_exception', $e);
117         }
118         try {
119             coursecat::create(array('name' => 'Cat2', 'idnumber' => '1'));
120             $this->fail('Duplicate idnumber exception expected in coursecat::create');
121         } catch (moodle_exception $e) {
122             $this->assertInstanceOf('moodle_exception', $e);
123         }
124         $cat2 = coursecat::create(array('name' => 'Cat2', 'idnumber' => '2'));
125         try {
126             $cat2->update(array('idnumber' => '1'));
127             $this->fail('Duplicate idnumber exception expected in coursecat::update');
128         } catch (moodle_exception $e) {
129             $this->assertInstanceOf('moodle_exception', $e);
130         }
131     }
133     public function test_visibility() {
134         $this->assign_capability('moodle/category:viewhiddencategories');
135         $this->assign_capability('moodle/category:manage');
137         // Create category 1 initially hidden.
138         $category1 = coursecat::create(array('name' => 'Cat1', 'visible' => 0));
139         $this->assertEquals(0, $category1->visible);
140         $this->assertEquals(0, $category1->visibleold);
142         // Create category 2 initially hidden as a child of hidden category 1.
143         $category2 = coursecat::create(array('name' => 'Cat2', 'visible' => 0, 'parent' => $category1->id));
144         $this->assertEquals(0, $category2->visible);
145         $this->assertEquals(0, $category2->visibleold);
147         // Create category 3 initially visible as a child of hidden category 1.
148         $category3 = coursecat::create(array('name' => 'Cat3', 'visible' => 1, 'parent' => $category1->id));
149         $this->assertEquals(0, $category3->visible);
150         $this->assertEquals(1, $category3->visibleold);
152         // Show category 1 and make sure that category 2 is hidden and category 3 is visible.
153         $category1->show();
154         $this->assertEquals(1, coursecat::get($category1->id)->visible);
155         $this->assertEquals(0, coursecat::get($category2->id)->visible);
156         $this->assertEquals(1, coursecat::get($category3->id)->visible);
158         // Create visible category 4.
159         $category4 = coursecat::create(array('name' => 'Cat4'));
160         $this->assertEquals(1, $category4->visible);
161         $this->assertEquals(1, $category4->visibleold);
163         // Create visible category 5 as a child of visible category 4.
164         $category5 = coursecat::create(array('name' => 'Cat5', 'parent' => $category4->id));
165         $this->assertEquals(1, $category5->visible);
166         $this->assertEquals(1, $category5->visibleold);
168         // Hide category 4 and make sure category 5 is hidden too.
169         $category4->hide();
170         $this->assertEquals(0, $category4->visible);
171         $this->assertEquals(0, $category4->visibleold);
172         $category5 = coursecat::get($category5->id); // We have to re-read from DB.
173         $this->assertEquals(0, $category5->visible);
174         $this->assertEquals(1, $category5->visibleold);
176         // Show category 4 and make sure category 5 is visible too.
177         $category4->show();
178         $this->assertEquals(1, $category4->visible);
179         $this->assertEquals(1, $category4->visibleold);
180         $category5 = coursecat::get($category5->id); // We have to re-read from DB.
181         $this->assertEquals(1, $category5->visible);
182         $this->assertEquals(1, $category5->visibleold);
184         // Move category 5 under hidden category 2 and make sure it became hidden.
185         $category5->change_parent($category2->id);
186         $this->assertEquals(0, $category5->visible);
187         $this->assertEquals(1, $category5->visibleold);
189         // Re-read object for category 5 from DB and check again.
190         $category5 = coursecat::get($category5->id);
191         $this->assertEquals(0, $category5->visible);
192         $this->assertEquals(1, $category5->visibleold);
194         // Rricky one! Move hidden category 5 under visible category ("Top") and make sure it is still hidden-
195         // WHY? Well, different people may expect different behaviour here. So better keep it hidden.
196         $category5->change_parent(0);
197         $this->assertEquals(0, $category5->visible);
198         $this->assertEquals(1, $category5->visibleold);
199     }
201     public function test_hierarchy() {
202         $this->assign_capability('moodle/category:viewhiddencategories');
203         $this->assign_capability('moodle/category:manage');
205         $category1 = coursecat::create(array('name' => 'Cat1'));
206         $category2 = coursecat::create(array('name' => 'Cat2', 'parent' => $category1->id));
207         $category3 = coursecat::create(array('name' => 'Cat3', 'parent' => $category1->id));
208         $category4 = coursecat::create(array('name' => 'Cat4', 'parent' => $category2->id));
210         // Check function get_children().
211         $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children()));
212         // Check function get_parents().
213         $this->assertEquals(array($category1->id, $category2->id), $category4->get_parents());
215         // Can not move category to itself or to it's children.
216         $this->assertFalse($category1->can_change_parent($category2->id));
217         $this->assertFalse($category2->can_change_parent($category2->id));
218         // Can move category to grandparent.
219         $this->assertTrue($category4->can_change_parent($category1->id));
221         try {
222             $category2->change_parent($category4->id);
223             $this->fail('Exception expected - can not move category');
224         } catch (moodle_exception $e) {
225             $this->assertInstanceOf('moodle_exception', $e);
226         }
228         $category4->change_parent(0);
229         $this->assertEquals(array(), $category4->get_parents());
230         $this->assertEquals(array($category2->id, $category3->id), array_keys($category1->get_children()));
231         $this->assertEquals(array(), array_keys($category2->get_children()));
232     }
234     public function test_update() {
235         $category1 = coursecat::create(array('name' => 'Cat1'));
236         $timecreated = $category1->timemodified;
237         $this->assertSame('Cat1', $category1->name);
238         $this->assertTrue(empty($category1->description));
239         sleep(2);
240         $testdescription = 'This is cat 1 а также русский текст';
241         $category1->update(array('description' => $testdescription));
242         $this->assertSame($testdescription, $category1->description);
243         $category1 = coursecat::get($category1->id);
244         $this->assertSame($testdescription, $category1->description);
245         cache_helper::purge_by_event('changesincoursecat');
246         $category1 = coursecat::get($category1->id);
247         $this->assertSame($testdescription, $category1->description);
249         $this->assertGreaterThan($timecreated, $category1->timemodified);
250     }
252     public function test_delete() {
253         global $DB;
255         $this->assign_capability('moodle/category:manage');
256         $this->assign_capability('moodle/course:create');
258         $initialcatid = $DB->get_field_sql('SELECT max(id) from {course_categories}');
260         $category1 = coursecat::create(array('name' => 'Cat1'));
261         $category2 = coursecat::create(array('name' => 'Cat2', 'parent' => $category1->id));
262         $category3 = coursecat::create(array('name' => 'Cat3'));
263         $category4 = coursecat::create(array('name' => 'Cat4', 'parent' => $category2->id));
265         $course1 = $this->getDataGenerator()->create_course(array('category' => $category2->id));
266         $course2 = $this->getDataGenerator()->create_course(array('category' => $category4->id));
267         $course3 = $this->getDataGenerator()->create_course(array('category' => $category4->id));
268         $course4 = $this->getDataGenerator()->create_course(array('category' => $category1->id));
270         // Now we have
271         // $category1
272         //   $category2
273         //      $category4
274         //        $course2
275         //        $course3
276         //      $course1
277         //   $course4
278         // $category3
279         // structure.
281         // Login as another user to test course:delete capability (user who created course can delete it within 24h even without cap).
282         $this->setUser($this->getDataGenerator()->create_user());
284         // Delete category 2 and move content to category 3.
285         $this->assertFalse($category2->can_move_content_to($category3->id)); // No luck!
286         // Add necessary capabilities.
287         $this->assign_capability('moodle/course:create', CAP_ALLOW, context_coursecat::instance($category3->id));
288         $this->assign_capability('moodle/category:manage');
289         $this->assertTrue($category2->can_move_content_to($category3->id)); // Hurray!
290         $category2->delete_move($category3->id);
292         // Make sure we have:
293         // $category1
294         //   $course4
295         // $category3
296         //    $category4
297         //      $course2
298         //      $course3
299         //    $course1
300         // structure.
302         $this->assertNull(coursecat::get($category2->id, IGNORE_MISSING, true));
303         $this->assertEquals(array(), $category1->get_children());
304         $this->assertEquals(array($category4->id), array_keys($category3->get_children()));
305         $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course2->id)));
306         $this->assertEquals($category4->id, $DB->get_field('course', 'category', array('id' => $course3->id)));
307         $this->assertEquals($category3->id, $DB->get_field('course', 'category', array('id' => $course1->id)));
309         // Delete category 3 completely.
310         $this->assertFalse($category3->can_delete_full()); // No luck!
311         // Add necessary capabilities.
312         $this->assign_capability('moodle/course:delete', CAP_ALLOW, context_coursecat::instance($category3->id));
313         $this->assertTrue($category3->can_delete_full()); // Hurray!
314         $category3->delete_full();
316         // Make sure we have:
317         // $category1
318         //   $course4
319         // structure.
321         // Note that we also have default 'Miscellaneous' category and default 'site' course.
322         $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course_categories} WHERE id > ?', array($initialcatid)));
323         $this->assertEquals($category1->id, $DB->get_field_sql('SELECT max(id) FROM {course_categories}'));
324         $this->assertEquals(1, $DB->get_field_sql('SELECT count(*) FROM {course} WHERE id <> ?', array(SITEID)));
325         $this->assertEquals(array('id' => $course4->id, 'category' => $category1->id),
326                 (array)$DB->get_record_sql('SELECT id, category from {course} where id <> ?', array(SITEID)));
327     }
329     public function test_get_children() {
330         $category1 = coursecat::create(array('name' => 'Cat1'));
331         $category2 = coursecat::create(array('name' => 'Cat2', 'parent' => $category1->id));
332         $category3 = coursecat::create(array('name' => 'Cat3', 'parent' => $category1->id, 'visible' => 0));
333         $category4 = coursecat::create(array('name' => 'Cat4', 'idnumber' => '12', 'parent' => $category1->id));
334         $category5 = coursecat::create(array('name' => 'Cat5', 'idnumber' => '11', 'parent' => $category1->id, 'visible' => 0));
335         $category6 = coursecat::create(array('name' => 'Cat6', 'idnumber' => '10', 'parent' => $category1->id));
336         $category7 = coursecat::create(array('name' => 'Cat0', 'parent' => $category1->id));
338         $children = $category1->get_children();
339         // User does not have the capability to view hidden categories, so the list should be
340         // 2, 4, 6, 7.
341         $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children));
342         $this->assertEquals(4, $category1->get_children_count());
344         $children = $category1->get_children(array('offset' => 2));
345         $this->assertEquals(array($category6->id, $category7->id), array_keys($children));
346         $this->assertEquals(4, $category1->get_children_count());
348         $children = $category1->get_children(array('limit' => 2));
349         $this->assertEquals(array($category2->id, $category4->id), array_keys($children));
351         $children = $category1->get_children(array('offset' => 1, 'limit' => 2));
352         $this->assertEquals(array($category4->id, $category6->id), array_keys($children));
354         $children = $category1->get_children(array('sort' => array('name' => 1)));
355         // Must be 7, 2, 4, 6.
356         $this->assertEquals(array($category7->id, $category2->id, $category4->id, $category6->id), array_keys($children));
358         $children = $category1->get_children(array('sort' => array('idnumber' => 1, 'name' => -1)));
359         // Must be 2, 7, 6, 4.
360         $this->assertEquals(array($category2->id, $category7->id, $category6->id, $category4->id), array_keys($children));
362         // Check that everything is all right after purging the caches.
363         cache_helper::purge_by_event('changesincoursecat');
364         $children = $category1->get_children();
365         $this->assertEquals(array($category2->id, $category4->id, $category6->id, $category7->id), array_keys($children));
366         $this->assertEquals(4, $category1->get_children_count());
367     }
369     public function test_get_search_courses() {
370         $cat1 = coursecat::create(array('name' => 'Cat1'));
371         $cat2 = coursecat::create(array('name' => 'Cat2', 'parent' => $cat1->id));
372         $c1 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 3', 'summary' => ' ', 'idnumber' => 'ID3'));
373         $c2 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 1', 'summary' => ' ', 'visible' => 0));
374         $c3 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Математика', 'summary' => ' Test '));
375         $c4 = $this->getDataGenerator()->create_course(array('category' => $cat1->id, 'fullname' => 'Test 4', 'summary' => ' ', 'idnumber' => 'ID4'));
377         $c5 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 5', 'summary' => ' '));
378         $c6 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Дискретная Математика', 'summary' => ' '));
379         $c7 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 7', 'summary' => ' ', 'visible' => 0));
380         $c8 = $this->getDataGenerator()->create_course(array('category' => $cat2->id, 'fullname' => 'Test 8', 'summary' => ' '));
382         // Get courses in category 1 (returned visible only because user is not enrolled).
383         $res = $cat1->get_courses(array('sortorder' => 1));
384         $this->assertEquals(array($c4->id, $c3->id, $c1->id), array_keys($res)); // Courses are added in reverse order.
385         $this->assertEquals(3, $cat1->get_courses_count());
387         // Get courses in category 1 recursively (returned visible only because user is not enrolled).
388         $res = $cat1->get_courses(array('recursive' => 1));
389         $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c6->id, $c5->id), array_keys($res));
390         $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1)));
392         // Get courses sorted by fullname.
393         $res = $cat1->get_courses(array('sort' => array('fullname' => 1)));
394         $this->assertEquals(array($c1->id, $c4->id, $c3->id), array_keys($res));
395         $this->assertEquals(3, $cat1->get_courses_count(array('sort' => array('fullname' => 1))));
397         // Get courses sorted by fullname recursively.
398         $res = $cat1->get_courses(array('recursive' => 1, 'sort' => array('fullname' => 1)));
399         $this->assertEquals(array($c1->id, $c4->id, $c5->id, $c8->id, $c6->id, $c3->id), array_keys($res));
400         $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'sort' => array('fullname' => 1))));
402         // Get courses sorted by fullname recursively, use offset and limit.
403         $res = $cat1->get_courses(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => -1)));
404         $this->assertEquals(array($c6->id, $c8->id), array_keys($res));
405         // Offset and limit do not affect get_courses_count().
406         $this->assertEquals(6, $cat1->get_courses_count(array('recursive' => 1, 'offset' => 1, 'limit' => 2, 'sort' => array('fullname' => 1))));
408         // Calling get_courses_count without prior call to get_courses().
409         $this->assertEquals(3, $cat2->get_courses_count(array('recursive' => 1, 'sort' => array('idnumber' => 1))));
411         // Search courses.
413         // Search by text.
414         $res = coursecat::search_courses(array('search' => 'Test'));
415         $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res));
416         $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test')));
418         // Search by text with specified offset and limit.
419         $options = array('sort' => array('fullname' => 1), 'offset' => 1, 'limit' => 2);
420         $res = coursecat::search_courses(array('search' => 'Test'), $options);
421         $this->assertEquals(array($c4->id, $c5->id), array_keys($res));
422         $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'Test'), $options));
424         // IMPORTANT: the tests below may fail on some databases
425         // case-insensitive search.
426         $res = coursecat::search_courses(array('search' => 'test'));
427         $this->assertEquals(array($c4->id, $c3->id, $c1->id, $c8->id, $c5->id), array_keys($res));
428         $this->assertEquals(5, coursecat::search_courses_count(array('search' => 'test')));
430         // Non-latin language search.
431         $res = coursecat::search_courses(array('search' => 'Математика'));
432         $this->assertEquals(array($c3->id, $c6->id), array_keys($res));
433         $this->assertEquals(2, coursecat::search_courses_count(array('search' => 'Математика'), array()));
434     }
436     public function test_course_contacts() {
437         global $DB, $CFG;
438         $teacherrole = $DB->get_record('role', array('shortname'=>'editingteacher'));
439         $managerrole = $DB->get_record('role', array('shortname'=>'manager'));
440         $studentrole = $DB->get_record('role', array('shortname'=>'student'));
441         $oldcoursecontact = $CFG->coursecontact;
443         $CFG->coursecontact = $managerrole->id. ','. $teacherrole->id;
445         /*
446          * User is listed in course contacts for the course if he has one of the
447          * "course contact" roles ($CFG->coursecontact) AND is enrolled in the course.
448          * If the user has several roles only the highest is displayed.
449          */
451         // Test case:
452         //
453         // == Cat1 (user2 has teacher role)
454         //   == Cat2
455         //     -- course21 (user2 is enrolled as manager) | [Expected] Manager: F2 L2
456         //     -- course22 (user2 is enrolled as student) | [Expected] Teacher: F2 L2
457         //     == Cat4 (user2 has manager role)
458         //       -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | [Expected] Manager: F5 L5, Teacher: F4 L4
459         //       -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2
460         //   == Cat3 (user3 has manager role)
461         //     -- course31 (user3 is enrolled as student) | [Expected] Manager: F3 L3
462         //     -- course32                                | [Expected]
463         //   -- course11 (user1 is enrolled as teacher)   | [Expected] Teacher: F1 L1
464         //   -- course12 (user1 has teacher role)         | [Expected]
465         //                also user4 is enrolled as teacher but enrolment is not active
466         $category = $course = $enrol = $user = array();
467         $category[1] = coursecat::create(array('name' => 'Cat1'))->id;
468         $category[2] = coursecat::create(array('name' => 'Cat2', 'parent' => $category[1]))->id;
469         $category[3] = coursecat::create(array('name' => 'Cat3', 'parent' => $category[1]))->id;
470         $category[4] = coursecat::create(array('name' => 'Cat4', 'parent' => $category[2]))->id;
471         foreach (array(1, 2, 3, 4) as $catid) {
472             foreach (array(1, 2) as $courseid) {
473                 $course[$catid][$courseid] = $this->getDataGenerator()->create_course(array('idnumber' => 'id'.$catid.$courseid,
474                     'category' => $category[$catid]))->id;
475                 $enrol[$catid][$courseid] = $DB->get_record('enrol', array('courseid'=>$course[$catid][$courseid], 'enrol'=>'manual'), '*', MUST_EXIST);
476             }
477         }
478         foreach (array(1, 2, 3, 4, 5) as $userid) {
479             $user[$userid] = $this->getDataGenerator()->create_user(array('firstname' => 'F'.$userid, 'lastname' => 'L'.$userid))->id;
480         }
482         $manual = enrol_get_plugin('manual');
484         // Cat1 (user2 has teacher role)
485         role_assign($teacherrole->id, $user[2], context_coursecat::instance($category[1]));
486         // course21 (user2 is enrolled as manager)
487         $manual->enrol_user($enrol[2][1], $user[2], $managerrole->id);
488         // course22 (user2 is enrolled as student)
489         $manual->enrol_user($enrol[2][2], $user[2], $studentrole->id);
490         // Cat4 (user2 has manager role)
491         role_assign($managerrole->id, $user[2], context_coursecat::instance($category[4]));
492         // course41 (user4 is enrolled as teacher, user5 is enrolled as manager)
493         $manual->enrol_user($enrol[4][1], $user[4], $teacherrole->id);
494         $manual->enrol_user($enrol[4][1], $user[5], $managerrole->id);
495         // course42 (user2 is enrolled as teacher)
496         $manual->enrol_user($enrol[4][2], $user[2], $teacherrole->id);
497         // Cat3 (user3 has manager role)
498         role_assign($managerrole->id, $user[3], context_coursecat::instance($category[3]));
499         // course31 (user3 is enrolled as student)
500         $manual->enrol_user($enrol[3][1], $user[3], $studentrole->id);
501         // course11 (user1 is enrolled as teacher)
502         $manual->enrol_user($enrol[1][1], $user[1], $teacherrole->id);
503         // -- course12 (user1 has teacher role)
504         //                also user4 is enrolled as teacher but enrolment is not active
505         role_assign($teacherrole->id, $user[1], context_course::instance($course[1][2]));
506         $manual->enrol_user($enrol[1][2], $user[4], $teacherrole->id, 0, 0, ENROL_USER_SUSPENDED);
508         $allcourses = coursecat::get(0)->get_courses(array('recursive' => true, 'coursecontacts' => true, 'sort' => array('idnumber' => 1)));
509         // Simplify the list of contacts for each course (similar as renderer would do).
510         $contacts = array();
511         foreach (array(1, 2, 3, 4) as $catid) {
512             foreach (array(1, 2) as $courseid) {
513                 $tmp = array();
514                 foreach ($allcourses[$course[$catid][$courseid]]->get_course_contacts() as $contact) {
515                     $tmp[] = $contact['rolename']. ': '. $contact['username'];
516                 }
517                 $contacts[$catid][$courseid] = join(', ', $tmp);
518             }
519         }
521         // Assert:
522         //     -- course21 (user2 is enrolled as manager) | Manager: F2 L2
523         $this->assertSame('Manager: F2 L2', $contacts[2][1]);
524         //     -- course22 (user2 is enrolled as student) | Teacher: F2 L2
525         $this->assertSame('Teacher: F2 L2', $contacts[2][2]);
526         //       -- course41 (user4 is enrolled as teacher, user5 is enrolled as manager) | Manager: F5 L5, Teacher: F4 L4
527         $this->assertSame('Manager: F5 L5, Teacher: F4 L4', $contacts[4][1]);
528         //       -- course42 (user2 is enrolled as teacher) | [Expected] Manager: F2 L2
529         $this->assertSame('Manager: F2 L2', $contacts[4][2]);
530         //     -- course31 (user3 is enrolled as student) | Manager: F3 L3
531         $this->assertSame('Manager: F3 L3', $contacts[3][1]);
532         //     -- course32                                |
533         $this->assertSame('', $contacts[3][2]);
534         //   -- course11 (user1 is enrolled as teacher)   | Teacher: F1 L1
535         $this->assertSame('Teacher: F1 L1', $contacts[1][1]);
536         //   -- course12 (user1 has teacher role)         |
537         $this->assertSame('', $contacts[1][2]);
539         $CFG->coursecontact = $oldcoursecontact;
540     }