Merge branch 'MDL-50357_master' of git://github.com/markn86/moodle
[moodle.git] / mod / forum / tests / lib_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  * The module forums tests
19  *
20  * @package    mod_forum
21  * @copyright  2013 Frédéric Massart
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once($CFG->dirroot . '/mod/forum/lib.php');
29 require_once($CFG->dirroot . '/rating/lib.php');
31 class mod_forum_lib_testcase extends advanced_testcase {
33     public function setUp() {
34         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
35         // tests using these functions.
36         \mod_forum\subscriptions::reset_forum_cache();
37     }
39     public function tearDown() {
40         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
41         // tests using these functions.
42         \mod_forum\subscriptions::reset_forum_cache();
43     }
45     public function test_forum_trigger_content_uploaded_event() {
46         $this->resetAfterTest();
48         $user = $this->getDataGenerator()->create_user();
49         $course = $this->getDataGenerator()->create_course();
50         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
51         $context = context_module::instance($forum->cmid);
53         $this->setUser($user->id);
54         $fakepost = (object) array('id' => 123, 'message' => 'Yay!', 'discussion' => 100);
55         $cm = get_coursemodule_from_instance('forum', $forum->id);
57         $fs = get_file_storage();
58         $dummy = (object) array(
59             'contextid' => $context->id,
60             'component' => 'mod_forum',
61             'filearea' => 'attachment',
62             'itemid' => $fakepost->id,
63             'filepath' => '/',
64             'filename' => 'myassignmnent.pdf'
65         );
66         $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
68         $data = new stdClass();
69         $sink = $this->redirectEvents();
70         forum_trigger_content_uploaded_event($fakepost, $cm, 'some triggered from value');
71         $events = $sink->get_events();
73         $this->assertCount(1, $events);
74         $event = reset($events);
75         $this->assertInstanceOf('\mod_forum\event\assessable_uploaded', $event);
76         $this->assertEquals($context->id, $event->contextid);
77         $this->assertEquals($fakepost->id, $event->objectid);
78         $this->assertEquals($fakepost->message, $event->other['content']);
79         $this->assertEquals($fakepost->discussion, $event->other['discussionid']);
80         $this->assertCount(1, $event->other['pathnamehashes']);
81         $this->assertEquals($fi->get_pathnamehash(), $event->other['pathnamehashes'][0]);
82         $expected = new stdClass();
83         $expected->modulename = 'forum';
84         $expected->name = 'some triggered from value';
85         $expected->cmid = $forum->cmid;
86         $expected->itemid = $fakepost->id;
87         $expected->courseid = $course->id;
88         $expected->userid = $user->id;
89         $expected->content = $fakepost->message;
90         $expected->pathnamehashes = array($fi->get_pathnamehash());
91         $this->assertEventLegacyData($expected, $event);
92         $this->assertEventContextNotUsed($event);
93     }
95     public function test_forum_get_courses_user_posted_in() {
96         $this->resetAfterTest();
98         $user1 = $this->getDataGenerator()->create_user();
99         $user2 = $this->getDataGenerator()->create_user();
100         $user3 = $this->getDataGenerator()->create_user();
102         $course1 = $this->getDataGenerator()->create_course();
103         $course2 = $this->getDataGenerator()->create_course();
104         $course3 = $this->getDataGenerator()->create_course();
106         // Create 3 forums, one in each course.
107         $record = new stdClass();
108         $record->course = $course1->id;
109         $forum1 = $this->getDataGenerator()->create_module('forum', $record);
111         $record = new stdClass();
112         $record->course = $course2->id;
113         $forum2 = $this->getDataGenerator()->create_module('forum', $record);
115         $record = new stdClass();
116         $record->course = $course3->id;
117         $forum3 = $this->getDataGenerator()->create_module('forum', $record);
119         // Add a second forum in course 1.
120         $record = new stdClass();
121         $record->course = $course1->id;
122         $forum4 = $this->getDataGenerator()->create_module('forum', $record);
124         // Add discussions to course 1 started by user1.
125         $record = new stdClass();
126         $record->course = $course1->id;
127         $record->userid = $user1->id;
128         $record->forum = $forum1->id;
129         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
131         $record = new stdClass();
132         $record->course = $course1->id;
133         $record->userid = $user1->id;
134         $record->forum = $forum4->id;
135         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
137         // Add discussions to course2 started by user1.
138         $record = new stdClass();
139         $record->course = $course2->id;
140         $record->userid = $user1->id;
141         $record->forum = $forum2->id;
142         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
144         // Add discussions to course 3 started by user2.
145         $record = new stdClass();
146         $record->course = $course3->id;
147         $record->userid = $user2->id;
148         $record->forum = $forum3->id;
149         $discussion3 = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
151         // Add post to course 3 by user1.
152         $record = new stdClass();
153         $record->course = $course3->id;
154         $record->userid = $user1->id;
155         $record->forum = $forum3->id;
156         $record->discussion = $discussion3->id;
157         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
159         // User 3 hasn't posted anything, so shouldn't get any results.
160         $user3courses = forum_get_courses_user_posted_in($user3);
161         $this->assertEmpty($user3courses);
163         // User 2 has only posted in course3.
164         $user2courses = forum_get_courses_user_posted_in($user2);
165         $this->assertCount(1, $user2courses);
166         $user2course = array_shift($user2courses);
167         $this->assertEquals($course3->id, $user2course->id);
168         $this->assertEquals($course3->shortname, $user2course->shortname);
170         // User 1 has posted in all 3 courses.
171         $user1courses = forum_get_courses_user_posted_in($user1);
172         $this->assertCount(3, $user1courses);
173         foreach ($user1courses as $course) {
174             $this->assertContains($course->id, array($course1->id, $course2->id, $course3->id));
175             $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname,
176                 $course3->shortname));
178         }
180         // User 1 has only started a discussion in course 1 and 2 though.
181         $user1courses = forum_get_courses_user_posted_in($user1, true);
182         $this->assertCount(2, $user1courses);
183         foreach ($user1courses as $course) {
184             $this->assertContains($course->id, array($course1->id, $course2->id));
185             $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname));
186         }
187     }
189     /**
190      * Test the logic in the forum_tp_can_track_forums() function.
191      */
192     public function test_forum_tp_can_track_forums() {
193         global $CFG;
195         $this->resetAfterTest();
197         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
198         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
199         $course = $this->getDataGenerator()->create_course();
200         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
201         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
203         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
204         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
206         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
207         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
209         // Allow force.
210         $CFG->forum_allowforcedreadtracking = 1;
212         // User on, forum off, should be off.
213         $result = forum_tp_can_track_forums($forumoff, $useron);
214         $this->assertEquals(false, $result);
216         // User on, forum on, should be on.
217         $result = forum_tp_can_track_forums($forumforce, $useron);
218         $this->assertEquals(true, $result);
220         // User on, forum optional, should be on.
221         $result = forum_tp_can_track_forums($forumoptional, $useron);
222         $this->assertEquals(true, $result);
224         // User off, forum off, should be off.
225         $result = forum_tp_can_track_forums($forumoff, $useroff);
226         $this->assertEquals(false, $result);
228         // User off, forum force, should be on.
229         $result = forum_tp_can_track_forums($forumforce, $useroff);
230         $this->assertEquals(true, $result);
232         // User off, forum optional, should be off.
233         $result = forum_tp_can_track_forums($forumoptional, $useroff);
234         $this->assertEquals(false, $result);
236         // Don't allow force.
237         $CFG->forum_allowforcedreadtracking = 0;
239         // User on, forum off, should be off.
240         $result = forum_tp_can_track_forums($forumoff, $useron);
241         $this->assertEquals(false, $result);
243         // User on, forum on, should be on.
244         $result = forum_tp_can_track_forums($forumforce, $useron);
245         $this->assertEquals(true, $result);
247         // User on, forum optional, should be on.
248         $result = forum_tp_can_track_forums($forumoptional, $useron);
249         $this->assertEquals(true, $result);
251         // User off, forum off, should be off.
252         $result = forum_tp_can_track_forums($forumoff, $useroff);
253         $this->assertEquals(false, $result);
255         // User off, forum force, should be off.
256         $result = forum_tp_can_track_forums($forumforce, $useroff);
257         $this->assertEquals(false, $result);
259         // User off, forum optional, should be off.
260         $result = forum_tp_can_track_forums($forumoptional, $useroff);
261         $this->assertEquals(false, $result);
263     }
265     /**
266      * Test the logic in the test_forum_tp_is_tracked() function.
267      */
268     public function test_forum_tp_is_tracked() {
269         global $CFG;
271         $this->resetAfterTest();
273         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
274         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
275         $course = $this->getDataGenerator()->create_course();
276         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
277         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
279         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
280         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
282         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
283         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
285         // Allow force.
286         $CFG->forum_allowforcedreadtracking = 1;
288         // User on, forum off, should be off.
289         $result = forum_tp_is_tracked($forumoff, $useron);
290         $this->assertEquals(false, $result);
292         // User on, forum force, should be on.
293         $result = forum_tp_is_tracked($forumforce, $useron);
294         $this->assertEquals(true, $result);
296         // User on, forum optional, should be on.
297         $result = forum_tp_is_tracked($forumoptional, $useron);
298         $this->assertEquals(true, $result);
300         // User off, forum off, should be off.
301         $result = forum_tp_is_tracked($forumoff, $useroff);
302         $this->assertEquals(false, $result);
304         // User off, forum force, should be on.
305         $result = forum_tp_is_tracked($forumforce, $useroff);
306         $this->assertEquals(true, $result);
308         // User off, forum optional, should be off.
309         $result = forum_tp_is_tracked($forumoptional, $useroff);
310         $this->assertEquals(false, $result);
312         // Don't allow force.
313         $CFG->forum_allowforcedreadtracking = 0;
315         // User on, forum off, should be off.
316         $result = forum_tp_is_tracked($forumoff, $useron);
317         $this->assertEquals(false, $result);
319         // User on, forum force, should be on.
320         $result = forum_tp_is_tracked($forumforce, $useron);
321         $this->assertEquals(true, $result);
323         // User on, forum optional, should be on.
324         $result = forum_tp_is_tracked($forumoptional, $useron);
325         $this->assertEquals(true, $result);
327         // User off, forum off, should be off.
328         $result = forum_tp_is_tracked($forumoff, $useroff);
329         $this->assertEquals(false, $result);
331         // User off, forum force, should be off.
332         $result = forum_tp_is_tracked($forumforce, $useroff);
333         $this->assertEquals(false, $result);
335         // User off, forum optional, should be off.
336         $result = forum_tp_is_tracked($forumoptional, $useroff);
337         $this->assertEquals(false, $result);
339         // Stop tracking so we can test again.
340         forum_tp_stop_tracking($forumforce->id, $useron->id);
341         forum_tp_stop_tracking($forumoptional->id, $useron->id);
342         forum_tp_stop_tracking($forumforce->id, $useroff->id);
343         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
345         // Allow force.
346         $CFG->forum_allowforcedreadtracking = 1;
348         // User on, preference off, forum force, should be on.
349         $result = forum_tp_is_tracked($forumforce, $useron);
350         $this->assertEquals(true, $result);
352         // User on, preference off, forum optional, should be on.
353         $result = forum_tp_is_tracked($forumoptional, $useron);
354         $this->assertEquals(false, $result);
356         // User off, preference off, forum force, should be on.
357         $result = forum_tp_is_tracked($forumforce, $useroff);
358         $this->assertEquals(true, $result);
360         // User off, preference off, forum optional, should be off.
361         $result = forum_tp_is_tracked($forumoptional, $useroff);
362         $this->assertEquals(false, $result);
364         // Don't allow force.
365         $CFG->forum_allowforcedreadtracking = 0;
367         // User on, preference off, forum force, should be on.
368         $result = forum_tp_is_tracked($forumforce, $useron);
369         $this->assertEquals(false, $result);
371         // User on, preference off, forum optional, should be on.
372         $result = forum_tp_is_tracked($forumoptional, $useron);
373         $this->assertEquals(false, $result);
375         // User off, preference off, forum force, should be off.
376         $result = forum_tp_is_tracked($forumforce, $useroff);
377         $this->assertEquals(false, $result);
379         // User off, preference off, forum optional, should be off.
380         $result = forum_tp_is_tracked($forumoptional, $useroff);
381         $this->assertEquals(false, $result);
382     }
384     /**
385      * Test the logic in the forum_tp_get_course_unread_posts() function.
386      */
387     public function test_forum_tp_get_course_unread_posts() {
388         global $CFG;
390         $this->resetAfterTest();
392         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
393         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
394         $course = $this->getDataGenerator()->create_course();
395         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
396         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
398         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
399         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
401         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
402         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
404         // Add discussions to the tracking off forum.
405         $record = new stdClass();
406         $record->course = $course->id;
407         $record->userid = $useron->id;
408         $record->forum = $forumoff->id;
409         $discussionoff = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
411         // Add discussions to the tracking forced forum.
412         $record = new stdClass();
413         $record->course = $course->id;
414         $record->userid = $useron->id;
415         $record->forum = $forumforce->id;
416         $discussionforce = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
418         // Add post to the tracking forced discussion.
419         $record = new stdClass();
420         $record->course = $course->id;
421         $record->userid = $useroff->id;
422         $record->forum = $forumforce->id;
423         $record->discussion = $discussionforce->id;
424         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
426         // Add discussions to the tracking optional forum.
427         $record = new stdClass();
428         $record->course = $course->id;
429         $record->userid = $useron->id;
430         $record->forum = $forumoptional->id;
431         $discussionoptional = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
433         // Allow force.
434         $CFG->forum_allowforcedreadtracking = 1;
436         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
437         $this->assertEquals(2, count($result));
438         $this->assertEquals(false, isset($result[$forumoff->id]));
439         $this->assertEquals(true, isset($result[$forumforce->id]));
440         $this->assertEquals(2, $result[$forumforce->id]->unread);
441         $this->assertEquals(true, isset($result[$forumoptional->id]));
442         $this->assertEquals(1, $result[$forumoptional->id]->unread);
444         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
445         $this->assertEquals(1, count($result));
446         $this->assertEquals(false, isset($result[$forumoff->id]));
447         $this->assertEquals(true, isset($result[$forumforce->id]));
448         $this->assertEquals(2, $result[$forumforce->id]->unread);
449         $this->assertEquals(false, isset($result[$forumoptional->id]));
451         // Don't allow force.
452         $CFG->forum_allowforcedreadtracking = 0;
454         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
455         $this->assertEquals(2, count($result));
456         $this->assertEquals(false, isset($result[$forumoff->id]));
457         $this->assertEquals(true, isset($result[$forumforce->id]));
458         $this->assertEquals(2, $result[$forumforce->id]->unread);
459         $this->assertEquals(true, isset($result[$forumoptional->id]));
460         $this->assertEquals(1, $result[$forumoptional->id]->unread);
462         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
463         $this->assertEquals(0, count($result));
464         $this->assertEquals(false, isset($result[$forumoff->id]));
465         $this->assertEquals(false, isset($result[$forumforce->id]));
466         $this->assertEquals(false, isset($result[$forumoptional->id]));
468         // Stop tracking so we can test again.
469         forum_tp_stop_tracking($forumforce->id, $useron->id);
470         forum_tp_stop_tracking($forumoptional->id, $useron->id);
471         forum_tp_stop_tracking($forumforce->id, $useroff->id);
472         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
474         // Allow force.
475         $CFG->forum_allowforcedreadtracking = 1;
477         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
478         $this->assertEquals(1, count($result));
479         $this->assertEquals(false, isset($result[$forumoff->id]));
480         $this->assertEquals(true, isset($result[$forumforce->id]));
481         $this->assertEquals(2, $result[$forumforce->id]->unread);
482         $this->assertEquals(false, isset($result[$forumoptional->id]));
484         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
485         $this->assertEquals(1, count($result));
486         $this->assertEquals(false, isset($result[$forumoff->id]));
487         $this->assertEquals(true, isset($result[$forumforce->id]));
488         $this->assertEquals(2, $result[$forumforce->id]->unread);
489         $this->assertEquals(false, isset($result[$forumoptional->id]));
491         // Don't allow force.
492         $CFG->forum_allowforcedreadtracking = 0;
494         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
495         $this->assertEquals(0, count($result));
496         $this->assertEquals(false, isset($result[$forumoff->id]));
497         $this->assertEquals(false, isset($result[$forumforce->id]));
498         $this->assertEquals(false, isset($result[$forumoptional->id]));
500         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
501         $this->assertEquals(0, count($result));
502         $this->assertEquals(false, isset($result[$forumoff->id]));
503         $this->assertEquals(false, isset($result[$forumforce->id]));
504         $this->assertEquals(false, isset($result[$forumoptional->id]));
505     }
507     /**
508      * Test the logic in the test_forum_tp_get_untracked_forums() function.
509      */
510     public function test_forum_tp_get_untracked_forums() {
511         global $CFG;
513         $this->resetAfterTest();
515         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
516         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
517         $course = $this->getDataGenerator()->create_course();
518         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
519         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
521         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
522         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
524         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
525         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
527         // Allow force.
528         $CFG->forum_allowforcedreadtracking = 1;
530         // On user with force on.
531         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
532         $this->assertEquals(1, count($result));
533         $this->assertEquals(true, isset($result[$forumoff->id]));
535         // Off user with force on.
536         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
537         $this->assertEquals(2, count($result));
538         $this->assertEquals(true, isset($result[$forumoff->id]));
539         $this->assertEquals(true, isset($result[$forumoptional->id]));
541         // Don't allow force.
542         $CFG->forum_allowforcedreadtracking = 0;
544         // On user with force off.
545         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
546         $this->assertEquals(1, count($result));
547         $this->assertEquals(true, isset($result[$forumoff->id]));
549         // Off user with force off.
550         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
551         $this->assertEquals(3, count($result));
552         $this->assertEquals(true, isset($result[$forumoff->id]));
553         $this->assertEquals(true, isset($result[$forumoptional->id]));
554         $this->assertEquals(true, isset($result[$forumforce->id]));
556         // Stop tracking so we can test again.
557         forum_tp_stop_tracking($forumforce->id, $useron->id);
558         forum_tp_stop_tracking($forumoptional->id, $useron->id);
559         forum_tp_stop_tracking($forumforce->id, $useroff->id);
560         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
562         // Allow force.
563         $CFG->forum_allowforcedreadtracking = 1;
565         // On user with force on.
566         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
567         $this->assertEquals(2, count($result));
568         $this->assertEquals(true, isset($result[$forumoff->id]));
569         $this->assertEquals(true, isset($result[$forumoptional->id]));
571         // Off user with force on.
572         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
573         $this->assertEquals(2, count($result));
574         $this->assertEquals(true, isset($result[$forumoff->id]));
575         $this->assertEquals(true, isset($result[$forumoptional->id]));
577         // Don't allow force.
578         $CFG->forum_allowforcedreadtracking = 0;
580         // On user with force off.
581         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
582         $this->assertEquals(3, count($result));
583         $this->assertEquals(true, isset($result[$forumoff->id]));
584         $this->assertEquals(true, isset($result[$forumoptional->id]));
585         $this->assertEquals(true, isset($result[$forumforce->id]));
587         // Off user with force off.
588         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
589         $this->assertEquals(3, count($result));
590         $this->assertEquals(true, isset($result[$forumoff->id]));
591         $this->assertEquals(true, isset($result[$forumoptional->id]));
592         $this->assertEquals(true, isset($result[$forumforce->id]));
593     }
595     /**
596      * Test subscription using automatic subscription on create.
597      */
598     public function test_forum_auto_subscribe_on_create() {
599         global $CFG;
601         $this->resetAfterTest();
603         $usercount = 5;
604         $course = $this->getDataGenerator()->create_course();
605         $users = array();
607         for ($i = 0; $i < $usercount; $i++) {
608             $user = $this->getDataGenerator()->create_user();
609             $users[] = $user;
610             $this->getDataGenerator()->enrol_user($user->id, $course->id);
611         }
613         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); // Automatic Subscription.
614         $forum = $this->getDataGenerator()->create_module('forum', $options);
616         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
617         $this->assertEquals($usercount, count($result));
618         foreach ($users as $user) {
619             $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
620         }
621     }
623     /**
624      * Test subscription using forced subscription on create.
625      */
626     public function test_forum_forced_subscribe_on_create() {
627         global $CFG;
629         $this->resetAfterTest();
631         $usercount = 5;
632         $course = $this->getDataGenerator()->create_course();
633         $users = array();
635         for ($i = 0; $i < $usercount; $i++) {
636             $user = $this->getDataGenerator()->create_user();
637             $users[] = $user;
638             $this->getDataGenerator()->enrol_user($user->id, $course->id);
639         }
641         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); // Forced subscription.
642         $forum = $this->getDataGenerator()->create_module('forum', $options);
644         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
645         $this->assertEquals($usercount, count($result));
646         foreach ($users as $user) {
647             $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
648         }
649     }
651     /**
652      * Test subscription using optional subscription on create.
653      */
654     public function test_forum_optional_subscribe_on_create() {
655         global $CFG;
657         $this->resetAfterTest();
659         $usercount = 5;
660         $course = $this->getDataGenerator()->create_course();
661         $users = array();
663         for ($i = 0; $i < $usercount; $i++) {
664             $user = $this->getDataGenerator()->create_user();
665             $users[] = $user;
666             $this->getDataGenerator()->enrol_user($user->id, $course->id);
667         }
669         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); // Subscription optional.
670         $forum = $this->getDataGenerator()->create_module('forum', $options);
672         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
673         // No subscriptions by default.
674         $this->assertEquals(0, count($result));
675         foreach ($users as $user) {
676             $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
677         }
678     }
680     /**
681      * Test subscription using disallow subscription on create.
682      */
683     public function test_forum_disallow_subscribe_on_create() {
684         global $CFG;
686         $this->resetAfterTest();
688         $usercount = 5;
689         $course = $this->getDataGenerator()->create_course();
690         $users = array();
692         for ($i = 0; $i < $usercount; $i++) {
693             $user = $this->getDataGenerator()->create_user();
694             $users[] = $user;
695             $this->getDataGenerator()->enrol_user($user->id, $course->id);
696         }
698         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); // Subscription prevented.
699         $forum = $this->getDataGenerator()->create_module('forum', $options);
701         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
702         // No subscriptions by default.
703         $this->assertEquals(0, count($result));
704         foreach ($users as $user) {
705             $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
706         }
707     }
709     /**
710      * Test that context fetching returns the appropriate context.
711      */
712     public function test_forum_get_context() {
713         global $DB, $PAGE;
715         $this->resetAfterTest();
717         // Setup test data.
718         $course = $this->getDataGenerator()->create_course();
719         $coursecontext = \context_course::instance($course->id);
721         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
722         $forum = $this->getDataGenerator()->create_module('forum', $options);
723         $forumcm = get_coursemodule_from_instance('forum', $forum->id);
724         $forumcontext = \context_module::instance($forumcm->id);
726         // First check that specifying the context results in the correct context being returned.
727         // Do this before we set up the page object and we should return from the coursemodule record.
728         // There should be no DB queries here because the context type was correct.
729         $startcount = $DB->perf_get_reads();
730         $result = forum_get_context($forum->id, $forumcontext);
731         $aftercount = $DB->perf_get_reads();
732         $this->assertEquals($forumcontext, $result);
733         $this->assertEquals(0, $aftercount - $startcount);
735         // And a context which is not the correct type.
736         // This tests will result in a DB query to fetch the course_module.
737         $startcount = $DB->perf_get_reads();
738         $result = forum_get_context($forum->id, $coursecontext);
739         $aftercount = $DB->perf_get_reads();
740         $this->assertEquals($forumcontext, $result);
741         $this->assertEquals(1, $aftercount - $startcount);
743         // Now do not specify a context at all.
744         // This tests will result in a DB query to fetch the course_module.
745         $startcount = $DB->perf_get_reads();
746         $result = forum_get_context($forum->id);
747         $aftercount = $DB->perf_get_reads();
748         $this->assertEquals($forumcontext, $result);
749         $this->assertEquals(1, $aftercount - $startcount);
751         // Set up the default page event to use the forum.
752         $PAGE = new moodle_page();
753         $PAGE->set_context($forumcontext);
754         $PAGE->set_cm($forumcm, $course, $forum);
756         // Now specify a context which is not a context_module.
757         // There should be no DB queries here because we use the PAGE.
758         $startcount = $DB->perf_get_reads();
759         $result = forum_get_context($forum->id, $coursecontext);
760         $aftercount = $DB->perf_get_reads();
761         $this->assertEquals($forumcontext, $result);
762         $this->assertEquals(0, $aftercount - $startcount);
764         // Now do not specify a context at all.
765         // There should be no DB queries here because we use the PAGE.
766         $startcount = $DB->perf_get_reads();
767         $result = forum_get_context($forum->id);
768         $aftercount = $DB->perf_get_reads();
769         $this->assertEquals($forumcontext, $result);
770         $this->assertEquals(0, $aftercount - $startcount);
772         // Now specify the page context of the course instead..
773         $PAGE = new moodle_page();
774         $PAGE->set_context($coursecontext);
776         // Now specify a context which is not a context_module.
777         // This tests will result in a DB query to fetch the course_module.
778         $startcount = $DB->perf_get_reads();
779         $result = forum_get_context($forum->id, $coursecontext);
780         $aftercount = $DB->perf_get_reads();
781         $this->assertEquals($forumcontext, $result);
782         $this->assertEquals(1, $aftercount - $startcount);
784         // Now do not specify a context at all.
785         // This tests will result in a DB query to fetch the course_module.
786         $startcount = $DB->perf_get_reads();
787         $result = forum_get_context($forum->id);
788         $aftercount = $DB->perf_get_reads();
789         $this->assertEquals($forumcontext, $result);
790         $this->assertEquals(1, $aftercount - $startcount);
791     }
793     /**
794      * Test getting the neighbour threads of a discussion.
795      */
796     public function test_forum_get_neighbours() {
797         global $CFG, $DB;
798         $this->resetAfterTest();
800         // Setup test data.
801         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
802         $course = $this->getDataGenerator()->create_course();
803         $user = $this->getDataGenerator()->create_user();
804         $user2 = $this->getDataGenerator()->create_user();
806         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
807         $cm = get_coursemodule_from_instance('forum', $forum->id);
808         $context = context_module::instance($cm->id);
810         $record = new stdClass();
811         $record->course = $course->id;
812         $record->userid = $user->id;
813         $record->forum = $forum->id;
814         $record->timemodified = time();
815         $disc1 = $forumgen->create_discussion($record);
816         $record->timemodified++;
817         $disc2 = $forumgen->create_discussion($record);
818         $record->timemodified++;
819         $disc3 = $forumgen->create_discussion($record);
820         $record->timemodified++;
821         $disc4 = $forumgen->create_discussion($record);
822         $record->timemodified++;
823         $disc5 = $forumgen->create_discussion($record);
825         // Getting the neighbours.
826         $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
827         $this->assertEmpty($neighbours['prev']);
828         $this->assertEquals($disc2->id, $neighbours['next']->id);
830         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
831         $this->assertEquals($disc1->id, $neighbours['prev']->id);
832         $this->assertEquals($disc3->id, $neighbours['next']->id);
834         $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
835         $this->assertEquals($disc2->id, $neighbours['prev']->id);
836         $this->assertEquals($disc4->id, $neighbours['next']->id);
838         $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum);
839         $this->assertEquals($disc3->id, $neighbours['prev']->id);
840         $this->assertEquals($disc5->id, $neighbours['next']->id);
842         $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
843         $this->assertEquals($disc4->id, $neighbours['prev']->id);
844         $this->assertEmpty($neighbours['next']);
846         // Post in some discussions. We manually update the discussion record because
847         // the data generator plays with timemodified in a way that would break this test.
848         $record->timemodified++;
849         $disc1->timemodified = $record->timemodified;
850         $DB->update_record('forum_discussions', $disc1);
852         $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
853         $this->assertEquals($disc4->id, $neighbours['prev']->id);
854         $this->assertEquals($disc1->id, $neighbours['next']->id);
856         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
857         $this->assertEmpty($neighbours['prev']);
858         $this->assertEquals($disc3->id, $neighbours['next']->id);
860         $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
861         $this->assertEquals($disc5->id, $neighbours['prev']->id);
862         $this->assertEmpty($neighbours['next']);
864         // After some discussions were created.
865         $record->timemodified++;
866         $disc6 = $forumgen->create_discussion($record);
867         $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum);
868         $this->assertEquals($disc1->id, $neighbours['prev']->id);
869         $this->assertEmpty($neighbours['next']);
871         $record->timemodified++;
872         $disc7 = $forumgen->create_discussion($record);
873         $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum);
874         $this->assertEquals($disc6->id, $neighbours['prev']->id);
875         $this->assertEmpty($neighbours['next']);
877         // Adding timed discussions.
878         $CFG->forum_enabletimedposts = true;
879         $now = $record->timemodified;
880         $past = $now - 60;
881         $future = $now + 60;
883         $record = new stdClass();
884         $record->course = $course->id;
885         $record->userid = $user->id;
886         $record->forum = $forum->id;
887         $record->timestart = $past;
888         $record->timeend = $future;
889         $record->timemodified = $now;
890         $record->timemodified++;
891         $disc8 = $forumgen->create_discussion($record);
892         $record->timemodified++;
893         $record->timestart = $future;
894         $record->timeend = 0;
895         $disc9 = $forumgen->create_discussion($record);
896         $record->timemodified++;
897         $record->timestart = 0;
898         $record->timeend = 0;
899         $disc10 = $forumgen->create_discussion($record);
900         $record->timemodified++;
901         $record->timestart = 0;
902         $record->timeend = $past;
903         $disc11 = $forumgen->create_discussion($record);
904         $record->timemodified++;
905         $record->timestart = $past;
906         $record->timeend = $future;
907         $disc12 = $forumgen->create_discussion($record);
908         $record->timemodified++;
909         $record->timestart = $future + 1; // Should be last post for those that can see it.
910         $record->timeend = 0;
911         $disc13 = $forumgen->create_discussion($record);
913         // Admin user ignores the timed settings of discussions.
914         // Post ordering taking into account timestart:
915         //  8 = t
916         // 10 = t+3
917         // 11 = t+4
918         // 12 = t+5
919         //  9 = t+60
920         // 13 = t+61.
921         $this->setAdminUser();
922         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
923         $this->assertEquals($disc7->id, $neighbours['prev']->id);
924         $this->assertEquals($disc10->id, $neighbours['next']->id);
926         $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
927         $this->assertEquals($disc12->id, $neighbours['prev']->id);
928         $this->assertEquals($disc13->id, $neighbours['next']->id);
930         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
931         $this->assertEquals($disc8->id, $neighbours['prev']->id);
932         $this->assertEquals($disc11->id, $neighbours['next']->id);
934         $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
935         $this->assertEquals($disc10->id, $neighbours['prev']->id);
936         $this->assertEquals($disc12->id, $neighbours['next']->id);
938         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
939         $this->assertEquals($disc11->id, $neighbours['prev']->id);
940         $this->assertEquals($disc9->id, $neighbours['next']->id);
942         $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum);
943         $this->assertEquals($disc9->id, $neighbours['prev']->id);
944         $this->assertEmpty($neighbours['next']);
946         // Normal user can see their own timed discussions.
947         $this->setUser($user);
948         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
949         $this->assertEquals($disc7->id, $neighbours['prev']->id);
950         $this->assertEquals($disc10->id, $neighbours['next']->id);
952         $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
953         $this->assertEquals($disc12->id, $neighbours['prev']->id);
954         $this->assertEquals($disc13->id, $neighbours['next']->id);
956         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
957         $this->assertEquals($disc8->id, $neighbours['prev']->id);
958         $this->assertEquals($disc11->id, $neighbours['next']->id);
960         $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
961         $this->assertEquals($disc10->id, $neighbours['prev']->id);
962         $this->assertEquals($disc12->id, $neighbours['next']->id);
964         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
965         $this->assertEquals($disc11->id, $neighbours['prev']->id);
966         $this->assertEquals($disc9->id, $neighbours['next']->id);
968         $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum);
969         $this->assertEquals($disc9->id, $neighbours['prev']->id);
970         $this->assertEmpty($neighbours['next']);
972         // Normal user does not ignore timed settings.
973         $this->setUser($user2);
974         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
975         $this->assertEquals($disc7->id, $neighbours['prev']->id);
976         $this->assertEquals($disc10->id, $neighbours['next']->id);
978         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
979         $this->assertEquals($disc8->id, $neighbours['prev']->id);
980         $this->assertEquals($disc12->id, $neighbours['next']->id);
982         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
983         $this->assertEquals($disc10->id, $neighbours['prev']->id);
984         $this->assertEmpty($neighbours['next']);
986         // Reset to normal mode.
987         $CFG->forum_enabletimedposts = false;
988         $this->setAdminUser();
990         // Two discussions with identical timemodified ignore each other.
991         $record->timemodified++;
992         $DB->update_record('forum_discussions', (object) array('id' => $disc3->id, 'timemodified' => $record->timemodified));
993         $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $record->timemodified));
994         $disc2 = $DB->get_record('forum_discussions', array('id' => $disc2->id));
995         $disc3 = $DB->get_record('forum_discussions', array('id' => $disc3->id));
997         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
998         $this->assertEquals($disc13->id, $neighbours['prev']->id);
999         $this->assertEmpty($neighbours['next']);
1001         $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1002         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1003         $this->assertEmpty($neighbours['next']);
1004     }
1006     /**
1007      * Test getting the neighbour threads of a blog-like forum.
1008      */
1009     public function test_forum_get_neighbours_blog() {
1010         global $CFG, $DB;
1011         $this->resetAfterTest();
1013         // Setup test data.
1014         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1015         $course = $this->getDataGenerator()->create_course();
1016         $user = $this->getDataGenerator()->create_user();
1017         $user2 = $this->getDataGenerator()->create_user();
1019         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog'));
1020         $cm = get_coursemodule_from_instance('forum', $forum->id);
1021         $context = context_module::instance($cm->id);
1023         $record = new stdClass();
1024         $record->course = $course->id;
1025         $record->userid = $user->id;
1026         $record->forum = $forum->id;
1027         $record->timemodified = time();
1028         $disc1 = $forumgen->create_discussion($record);
1029         $record->timemodified++;
1030         $disc2 = $forumgen->create_discussion($record);
1031         $record->timemodified++;
1032         $disc3 = $forumgen->create_discussion($record);
1033         $record->timemodified++;
1034         $disc4 = $forumgen->create_discussion($record);
1035         $record->timemodified++;
1036         $disc5 = $forumgen->create_discussion($record);
1038         // Getting the neighbours.
1039         $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
1040         $this->assertEmpty($neighbours['prev']);
1041         $this->assertEquals($disc2->id, $neighbours['next']->id);
1043         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1044         $this->assertEquals($disc1->id, $neighbours['prev']->id);
1045         $this->assertEquals($disc3->id, $neighbours['next']->id);
1047         $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1048         $this->assertEquals($disc2->id, $neighbours['prev']->id);
1049         $this->assertEquals($disc4->id, $neighbours['next']->id);
1051         $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum);
1052         $this->assertEquals($disc3->id, $neighbours['prev']->id);
1053         $this->assertEquals($disc5->id, $neighbours['next']->id);
1055         $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
1056         $this->assertEquals($disc4->id, $neighbours['prev']->id);
1057         $this->assertEmpty($neighbours['next']);
1059         // Make sure that the thread's timemodified does not affect the order.
1060         $record->timemodified++;
1061         $disc1->timemodified = $record->timemodified;
1062         $DB->update_record('forum_discussions', $disc1);
1064         $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
1065         $this->assertEmpty($neighbours['prev']);
1066         $this->assertEquals($disc2->id, $neighbours['next']->id);
1068         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1069         $this->assertEquals($disc1->id, $neighbours['prev']->id);
1070         $this->assertEquals($disc3->id, $neighbours['next']->id);
1072         // Add another blog post.
1073         $record->timemodified++;
1074         $disc6 = $forumgen->create_discussion($record);
1075         $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum);
1076         $this->assertEquals($disc5->id, $neighbours['prev']->id);
1077         $this->assertEmpty($neighbours['next']);
1079         $record->timemodified++;
1080         $disc7 = $forumgen->create_discussion($record);
1081         $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum);
1082         $this->assertEquals($disc6->id, $neighbours['prev']->id);
1083         $this->assertEmpty($neighbours['next']);
1085         // Adding timed discussions.
1086         $CFG->forum_enabletimedposts = true;
1087         $now = $record->timemodified;
1088         $past = $now - 60;
1089         $future = $now + 60;
1091         $record = new stdClass();
1092         $record->course = $course->id;
1093         $record->userid = $user->id;
1094         $record->forum = $forum->id;
1095         $record->timestart = $past;
1096         $record->timeend = $future;
1097         $record->timemodified = $now;
1098         $record->timemodified++;
1099         $disc8 = $forumgen->create_discussion($record);
1100         $record->timemodified++;
1101         $record->timestart = $future;
1102         $record->timeend = 0;
1103         $disc9 = $forumgen->create_discussion($record);
1104         $record->timemodified++;
1105         $record->timestart = 0;
1106         $record->timeend = 0;
1107         $disc10 = $forumgen->create_discussion($record);
1108         $record->timemodified++;
1109         $record->timestart = 0;
1110         $record->timeend = $past;
1111         $disc11 = $forumgen->create_discussion($record);
1112         $record->timemodified++;
1113         $record->timestart = $past;
1114         $record->timeend = $future;
1115         $disc12 = $forumgen->create_discussion($record);
1117         // Admin user ignores the timed settings of discussions.
1118         $this->setAdminUser();
1119         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1120         $this->assertEquals($disc7->id, $neighbours['prev']->id);
1121         $this->assertEquals($disc9->id, $neighbours['next']->id);
1123         $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
1124         $this->assertEquals($disc8->id, $neighbours['prev']->id);
1125         $this->assertEquals($disc10->id, $neighbours['next']->id);
1127         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1128         $this->assertEquals($disc9->id, $neighbours['prev']->id);
1129         $this->assertEquals($disc11->id, $neighbours['next']->id);
1131         $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
1132         $this->assertEquals($disc10->id, $neighbours['prev']->id);
1133         $this->assertEquals($disc12->id, $neighbours['next']->id);
1135         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1136         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1137         $this->assertEmpty($neighbours['next']);
1139         // Normal user can see their own timed discussions.
1140         $this->setUser($user);
1141         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1142         $this->assertEquals($disc7->id, $neighbours['prev']->id);
1143         $this->assertEquals($disc9->id, $neighbours['next']->id);
1145         $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
1146         $this->assertEquals($disc8->id, $neighbours['prev']->id);
1147         $this->assertEquals($disc10->id, $neighbours['next']->id);
1149         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1150         $this->assertEquals($disc9->id, $neighbours['prev']->id);
1151         $this->assertEquals($disc11->id, $neighbours['next']->id);
1153         $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
1154         $this->assertEquals($disc10->id, $neighbours['prev']->id);
1155         $this->assertEquals($disc12->id, $neighbours['next']->id);
1157         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1158         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1159         $this->assertEmpty($neighbours['next']);
1161         // Normal user does not ignore timed settings.
1162         $this->setUser($user2);
1163         $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1164         $this->assertEquals($disc7->id, $neighbours['prev']->id);
1165         $this->assertEquals($disc10->id, $neighbours['next']->id);
1167         $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1168         $this->assertEquals($disc8->id, $neighbours['prev']->id);
1169         $this->assertEquals($disc12->id, $neighbours['next']->id);
1171         $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1172         $this->assertEquals($disc10->id, $neighbours['prev']->id);
1173         $this->assertEmpty($neighbours['next']);
1175         // Reset to normal mode.
1176         $CFG->forum_enabletimedposts = false;
1177         $this->setAdminUser();
1179         // Two blog posts with identical creation time ignore each other.
1180         $record->timemodified++;
1181         $DB->update_record('forum_posts', (object) array('id' => $disc2->firstpost, 'created' => $record->timemodified));
1182         $DB->update_record('forum_posts', (object) array('id' => $disc3->firstpost, 'created' => $record->timemodified));
1184         $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1185         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1186         $this->assertEmpty($neighbours['next']);
1188         $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1189         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1190         $this->assertEmpty($neighbours['next']);
1191     }
1193     /**
1194      * Test getting the neighbour threads of a discussion.
1195      */
1196     public function test_forum_get_neighbours_with_groups() {
1197         $this->resetAfterTest();
1199         // Setup test data.
1200         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1201         $course = $this->getDataGenerator()->create_course();
1202         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1203         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1204         $user1 = $this->getDataGenerator()->create_user();
1205         $user2 = $this->getDataGenerator()->create_user();
1206         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
1207         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
1208         $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id));
1210         $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS));
1211         $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS));
1212         $cm1 = get_coursemodule_from_instance('forum', $forum1->id);
1213         $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
1214         $context1 = context_module::instance($cm1->id);
1215         $context2 = context_module::instance($cm2->id);
1217         // Creating discussions in both forums.
1218         $record = new stdClass();
1219         $record->course = $course->id;
1220         $record->userid = $user1->id;
1221         $record->forum = $forum1->id;
1222         $record->groupid = $group1->id;
1223         $record->timemodified = time();
1224         $disc11 = $forumgen->create_discussion($record);
1225         $record->forum = $forum2->id;
1226         $record->timemodified++;
1227         $disc21 = $forumgen->create_discussion($record);
1229         $record->timemodified++;
1230         $record->userid = $user2->id;
1231         $record->forum = $forum1->id;
1232         $record->groupid = $group2->id;
1233         $disc12 = $forumgen->create_discussion($record);
1234         $record->forum = $forum2->id;
1235         $disc22 = $forumgen->create_discussion($record);
1237         $record->timemodified++;
1238         $record->userid = $user1->id;
1239         $record->forum = $forum1->id;
1240         $record->groupid = null;
1241         $disc13 = $forumgen->create_discussion($record);
1242         $record->forum = $forum2->id;
1243         $disc23 = $forumgen->create_discussion($record);
1245         $record->timemodified++;
1246         $record->userid = $user2->id;
1247         $record->forum = $forum1->id;
1248         $record->groupid = $group2->id;
1249         $disc14 = $forumgen->create_discussion($record);
1250         $record->forum = $forum2->id;
1251         $disc24 = $forumgen->create_discussion($record);
1253         $record->timemodified++;
1254         $record->userid = $user1->id;
1255         $record->forum = $forum1->id;
1256         $record->groupid = $group1->id;
1257         $disc15 = $forumgen->create_discussion($record);
1258         $record->forum = $forum2->id;
1259         $disc25 = $forumgen->create_discussion($record);
1261         // Admin user can see all groups.
1262         $this->setAdminUser();
1263         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1264         $this->assertEmpty($neighbours['prev']);
1265         $this->assertEquals($disc12->id, $neighbours['next']->id);
1266         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1267         $this->assertEmpty($neighbours['prev']);
1268         $this->assertEquals($disc22->id, $neighbours['next']->id);
1270         $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1271         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1272         $this->assertEquals($disc13->id, $neighbours['next']->id);
1273         $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1274         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1275         $this->assertEquals($disc23->id, $neighbours['next']->id);
1277         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1278         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1279         $this->assertEquals($disc14->id, $neighbours['next']->id);
1280         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1281         $this->assertEquals($disc22->id, $neighbours['prev']->id);
1282         $this->assertEquals($disc24->id, $neighbours['next']->id);
1284         $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1);
1285         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1286         $this->assertEquals($disc15->id, $neighbours['next']->id);
1287         $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1288         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1289         $this->assertEquals($disc25->id, $neighbours['next']->id);
1291         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1292         $this->assertEquals($disc14->id, $neighbours['prev']->id);
1293         $this->assertEmpty($neighbours['next']);
1294         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1295         $this->assertEquals($disc24->id, $neighbours['prev']->id);
1296         $this->assertEmpty($neighbours['next']);
1298         // Admin user is only viewing group 1.
1299         $_POST['group'] = $group1->id;
1300         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1301         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1303         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1304         $this->assertEmpty($neighbours['prev']);
1305         $this->assertEquals($disc13->id, $neighbours['next']->id);
1306         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1307         $this->assertEmpty($neighbours['prev']);
1308         $this->assertEquals($disc23->id, $neighbours['next']->id);
1310         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1311         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1312         $this->assertEquals($disc15->id, $neighbours['next']->id);
1313         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1314         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1315         $this->assertEquals($disc25->id, $neighbours['next']->id);
1317         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1318         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1319         $this->assertEmpty($neighbours['next']);
1320         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1321         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1322         $this->assertEmpty($neighbours['next']);
1324         // Normal user viewing non-grouped posts (this is only possible in visible groups).
1325         $this->setUser($user1);
1326         $_POST['group'] = 0;
1327         $this->assertEquals(0, groups_get_activity_group($cm1, true));
1329         // They can see anything in visible groups.
1330         $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1331         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1332         $this->assertEquals($disc13->id, $neighbours['next']->id);
1333         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1334         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1335         $this->assertEquals($disc14->id, $neighbours['next']->id);
1337         // Normal user, orphan of groups, can only see non-grouped posts in separate groups.
1338         $this->setUser($user2);
1339         $_POST['group'] = 0;
1340         $this->assertEquals(0, groups_get_activity_group($cm2, true));
1342         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1343         $this->assertEmpty($neighbours['prev']);
1344         $this->assertEmpty($neighbours['next']);
1346         $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1347         $this->assertEmpty($neighbours['prev']);
1348         $this->assertEquals($disc23->id, $neighbours['next']->id);
1350         $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1351         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1352         $this->assertEmpty($neighbours['next']);
1354         // Switching to viewing group 1.
1355         $this->setUser($user1);
1356         $_POST['group'] = $group1->id;
1357         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1358         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1360         // They can see non-grouped or same group.
1361         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1362         $this->assertEmpty($neighbours['prev']);
1363         $this->assertEquals($disc13->id, $neighbours['next']->id);
1364         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1365         $this->assertEmpty($neighbours['prev']);
1366         $this->assertEquals($disc23->id, $neighbours['next']->id);
1368         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1369         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1370         $this->assertEquals($disc15->id, $neighbours['next']->id);
1371         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1372         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1373         $this->assertEquals($disc25->id, $neighbours['next']->id);
1375         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1376         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1377         $this->assertEmpty($neighbours['next']);
1378         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1379         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1380         $this->assertEmpty($neighbours['next']);
1382         // Querying the neighbours of a discussion passing the wrong CM.
1383         $this->setExpectedException('coding_exception');
1384         forum_get_discussion_neighbours($cm2, $disc11, $forum2);
1385     }
1387     /**
1388      * Test getting the neighbour threads of a blog-like forum with groups involved.
1389      */
1390     public function test_forum_get_neighbours_with_groups_blog() {
1391         $this->resetAfterTest();
1393         // Setup test data.
1394         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1395         $course = $this->getDataGenerator()->create_course();
1396         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1397         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1398         $user1 = $this->getDataGenerator()->create_user();
1399         $user2 = $this->getDataGenerator()->create_user();
1400         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
1401         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
1402         $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id));
1404         $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog',
1405                 'groupmode' => VISIBLEGROUPS));
1406         $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog',
1407                 'groupmode' => SEPARATEGROUPS));
1408         $cm1 = get_coursemodule_from_instance('forum', $forum1->id);
1409         $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
1410         $context1 = context_module::instance($cm1->id);
1411         $context2 = context_module::instance($cm2->id);
1413         // Creating blog posts in both forums.
1414         $record = new stdClass();
1415         $record->course = $course->id;
1416         $record->userid = $user1->id;
1417         $record->forum = $forum1->id;
1418         $record->groupid = $group1->id;
1419         $record->timemodified = time();
1420         $disc11 = $forumgen->create_discussion($record);
1421         $record->forum = $forum2->id;
1422         $record->timemodified++;
1423         $disc21 = $forumgen->create_discussion($record);
1425         $record->timemodified++;
1426         $record->userid = $user2->id;
1427         $record->forum = $forum1->id;
1428         $record->groupid = $group2->id;
1429         $disc12 = $forumgen->create_discussion($record);
1430         $record->forum = $forum2->id;
1431         $disc22 = $forumgen->create_discussion($record);
1433         $record->timemodified++;
1434         $record->userid = $user1->id;
1435         $record->forum = $forum1->id;
1436         $record->groupid = null;
1437         $disc13 = $forumgen->create_discussion($record);
1438         $record->forum = $forum2->id;
1439         $disc23 = $forumgen->create_discussion($record);
1441         $record->timemodified++;
1442         $record->userid = $user2->id;
1443         $record->forum = $forum1->id;
1444         $record->groupid = $group2->id;
1445         $disc14 = $forumgen->create_discussion($record);
1446         $record->forum = $forum2->id;
1447         $disc24 = $forumgen->create_discussion($record);
1449         $record->timemodified++;
1450         $record->userid = $user1->id;
1451         $record->forum = $forum1->id;
1452         $record->groupid = $group1->id;
1453         $disc15 = $forumgen->create_discussion($record);
1454         $record->forum = $forum2->id;
1455         $disc25 = $forumgen->create_discussion($record);
1457         // Admin user can see all groups.
1458         $this->setAdminUser();
1459         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1460         $this->assertEmpty($neighbours['prev']);
1461         $this->assertEquals($disc12->id, $neighbours['next']->id);
1462         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1463         $this->assertEmpty($neighbours['prev']);
1464         $this->assertEquals($disc22->id, $neighbours['next']->id);
1466         $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1467         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1468         $this->assertEquals($disc13->id, $neighbours['next']->id);
1469         $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1470         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1471         $this->assertEquals($disc23->id, $neighbours['next']->id);
1473         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1474         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1475         $this->assertEquals($disc14->id, $neighbours['next']->id);
1476         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1477         $this->assertEquals($disc22->id, $neighbours['prev']->id);
1478         $this->assertEquals($disc24->id, $neighbours['next']->id);
1480         $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1);
1481         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1482         $this->assertEquals($disc15->id, $neighbours['next']->id);
1483         $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1484         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1485         $this->assertEquals($disc25->id, $neighbours['next']->id);
1487         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1488         $this->assertEquals($disc14->id, $neighbours['prev']->id);
1489         $this->assertEmpty($neighbours['next']);
1490         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1491         $this->assertEquals($disc24->id, $neighbours['prev']->id);
1492         $this->assertEmpty($neighbours['next']);
1494         // Admin user is only viewing group 1.
1495         $_POST['group'] = $group1->id;
1496         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1497         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1499         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1500         $this->assertEmpty($neighbours['prev']);
1501         $this->assertEquals($disc13->id, $neighbours['next']->id);
1502         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1503         $this->assertEmpty($neighbours['prev']);
1504         $this->assertEquals($disc23->id, $neighbours['next']->id);
1506         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1507         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1508         $this->assertEquals($disc15->id, $neighbours['next']->id);
1509         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1510         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1511         $this->assertEquals($disc25->id, $neighbours['next']->id);
1513         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1514         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1515         $this->assertEmpty($neighbours['next']);
1516         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1517         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1518         $this->assertEmpty($neighbours['next']);
1520         // Normal user viewing non-grouped posts (this is only possible in visible groups).
1521         $this->setUser($user1);
1522         $_POST['group'] = 0;
1523         $this->assertEquals(0, groups_get_activity_group($cm1, true));
1525         // They can see anything in visible groups.
1526         $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1527         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1528         $this->assertEquals($disc13->id, $neighbours['next']->id);
1529         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1530         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1531         $this->assertEquals($disc14->id, $neighbours['next']->id);
1533         // Normal user, orphan of groups, can only see non-grouped posts in separate groups.
1534         $this->setUser($user2);
1535         $_POST['group'] = 0;
1536         $this->assertEquals(0, groups_get_activity_group($cm2, true));
1538         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1539         $this->assertEmpty($neighbours['prev']);
1540         $this->assertEmpty($neighbours['next']);
1542         $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1543         $this->assertEmpty($neighbours['prev']);
1544         $this->assertEquals($disc23->id, $neighbours['next']->id);
1546         $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1547         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1548         $this->assertEmpty($neighbours['next']);
1550         // Switching to viewing group 1.
1551         $this->setUser($user1);
1552         $_POST['group'] = $group1->id;
1553         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1554         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1556         // They can see non-grouped or same group.
1557         $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1558         $this->assertEmpty($neighbours['prev']);
1559         $this->assertEquals($disc13->id, $neighbours['next']->id);
1560         $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1561         $this->assertEmpty($neighbours['prev']);
1562         $this->assertEquals($disc23->id, $neighbours['next']->id);
1564         $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1565         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1566         $this->assertEquals($disc15->id, $neighbours['next']->id);
1567         $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1568         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1569         $this->assertEquals($disc25->id, $neighbours['next']->id);
1571         $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1572         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1573         $this->assertEmpty($neighbours['next']);
1574         $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1575         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1576         $this->assertEmpty($neighbours['next']);
1578         // Querying the neighbours of a discussion passing the wrong CM.
1579         $this->setExpectedException('coding_exception');
1580         forum_get_discussion_neighbours($cm2, $disc11, $forum2);
1581     }
1583     public function test_count_discussion_replies_basic() {
1584         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1586         // Count the discussion replies in the forum.
1587         $result = forum_count_discussion_replies($forum->id);
1588         $this->assertCount(10, $result);
1589     }
1591     public function test_count_discussion_replies_limited() {
1592         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1593         // Adding limits shouldn't make a difference.
1594         $result = forum_count_discussion_replies($forum->id, "", 20);
1595         $this->assertCount(10, $result);
1596     }
1598     public function test_count_discussion_replies_paginated() {
1599         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1600         // Adding paging shouldn't make any difference.
1601         $result = forum_count_discussion_replies($forum->id, "", -1, 0, 100);
1602         $this->assertCount(10, $result);
1603     }
1605     public function test_count_discussion_replies_paginated_sorted() {
1606         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1607         // Specifying the forumsort should also give a good result. This follows a different path.
1608         $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 100);
1609         $this->assertCount(10, $result);
1610         foreach ($result as $row) {
1611             // Grab the first discussionid.
1612             $discussionid = array_shift($discussionids);
1613             $this->assertEquals($discussionid, $row->discussion);
1614         }
1615     }
1617     public function test_count_discussion_replies_limited_sorted() {
1618         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1619         // Adding limits, and a forumsort shouldn't make a difference.
1620         $result = forum_count_discussion_replies($forum->id, "d.id asc", 20);
1621         $this->assertCount(10, $result);
1622         foreach ($result as $row) {
1623             // Grab the first discussionid.
1624             $discussionid = array_shift($discussionids);
1625             $this->assertEquals($discussionid, $row->discussion);
1626         }
1627     }
1629     public function test_count_discussion_replies_paginated_sorted_small() {
1630         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1631         // Grabbing a smaller subset and they should be ordered as expected.
1632         $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 5);
1633         $this->assertCount(5, $result);
1634         foreach ($result as $row) {
1635             // Grab the first discussionid.
1636             $discussionid = array_shift($discussionids);
1637             $this->assertEquals($discussionid, $row->discussion);
1638         }
1639     }
1641     public function test_count_discussion_replies_paginated_sorted_small_reverse() {
1642         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1643         // Grabbing a smaller subset and they should be ordered as expected.
1644         $result = forum_count_discussion_replies($forum->id, "d.id desc", -1, 0, 5);
1645         $this->assertCount(5, $result);
1646         foreach ($result as $row) {
1647             // Grab the last discussionid.
1648             $discussionid = array_pop($discussionids);
1649             $this->assertEquals($discussionid, $row->discussion);
1650         }
1651     }
1653     public function test_count_discussion_replies_limited_sorted_small_reverse() {
1654         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1655         // Adding limits, and a forumsort shouldn't make a difference.
1656         $result = forum_count_discussion_replies($forum->id, "d.id desc", 5);
1657         $this->assertCount(5, $result);
1658         foreach ($result as $row) {
1659             // Grab the last discussionid.
1660             $discussionid = array_pop($discussionids);
1661             $this->assertEquals($discussionid, $row->discussion);
1662         }
1663     }
1665     public function test_forum_view() {
1666         global $CFG;
1668         $CFG->enablecompletion = 1;
1669         $this->resetAfterTest();
1671         // Setup test data.
1672         $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
1673         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
1674                                                             array('completion' => 2, 'completionview' => 1));
1675         $context = context_module::instance($forum->cmid);
1676         $cm = get_coursemodule_from_instance('forum', $forum->id);
1678         // Trigger and capture the event.
1679         $sink = $this->redirectEvents();
1681         $this->setAdminUser();
1682         forum_view($forum, $course, $cm, $context);
1684         $events = $sink->get_events();
1685         // 2 additional events thanks to completion.
1686         $this->assertCount(3, $events);
1687         $event = array_pop($events);
1689         // Checking that the event contains the expected values.
1690         $this->assertInstanceOf('\mod_forum\event\course_module_viewed', $event);
1691         $this->assertEquals($context, $event->get_context());
1692         $url = new \moodle_url('/mod/forum/view.php', array('f' => $forum->id));
1693         $this->assertEquals($url, $event->get_url());
1694         $this->assertEventContextNotUsed($event);
1695         $this->assertNotEmpty($event->get_name());
1697         // Check completion status.
1698         $completion = new completion_info($course);
1699         $completiondata = $completion->get_data($cm);
1700         $this->assertEquals(1, $completiondata->completionstate);
1702     }
1704     /**
1705      * Test forum_discussion_view.
1706      */
1707     public function test_forum_discussion_view() {
1708         global $CFG, $USER;
1710         $this->resetAfterTest();
1712         // Setup test data.
1713         $course = $this->getDataGenerator()->create_course();
1714         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1715         $discussion = $this->create_single_discussion_with_replies($forum, $USER, 2);
1717         $context = context_module::instance($forum->cmid);
1718         $cm = get_coursemodule_from_instance('forum', $forum->id);
1720         // Trigger and capture the event.
1721         $sink = $this->redirectEvents();
1723         $this->setAdminUser();
1724         forum_discussion_view($context, $forum, $discussion);
1726         $events = $sink->get_events();
1727         $this->assertCount(1, $events);
1728         $event = array_pop($events);
1730         // Checking that the event contains the expected values.
1731         $this->assertInstanceOf('\mod_forum\event\discussion_viewed', $event);
1732         $this->assertEquals($context, $event->get_context());
1733         $expected = array($course->id, 'forum', 'view discussion', "discuss.php?d={$discussion->id}",
1734             $discussion->id, $forum->cmid);
1735         $this->assertEventLegacyLogData($expected, $event);
1736         $this->assertEventContextNotUsed($event);
1738         $this->assertNotEmpty($event->get_name());
1740     }
1742     /**
1743      * Create a new course, forum, and user with a number of discussions and replies.
1744      *
1745      * @param int $discussioncount The number of discussions to create
1746      * @param int $replycount The number of replies to create in each discussion
1747      * @return array Containing the created forum object, and the ids of the created discussions.
1748      */
1749     protected function create_multiple_discussions_with_replies($discussioncount, $replycount) {
1750         $this->resetAfterTest();
1752         // Setup the content.
1753         $user = $this->getDataGenerator()->create_user();
1754         $course = $this->getDataGenerator()->create_course();
1755         $record = new stdClass();
1756         $record->course = $course->id;
1757         $forum = $this->getDataGenerator()->create_module('forum', $record);
1759         // Create 10 discussions with replies.
1760         $discussionids = array();
1761         for ($i = 0; $i < $discussioncount; $i++) {
1762             $discussion = $this->create_single_discussion_with_replies($forum, $user, $replycount);
1763             $discussionids[] = $discussion->id;
1764         }
1765         return array($forum, $discussionids);
1766     }
1768     /**
1769      * Create a discussion with a number of replies.
1770      *
1771      * @param object $forum The forum which has been created
1772      * @param object $user The user making the discussion and replies
1773      * @param int $replycount The number of replies
1774      * @return object $discussion
1775      */
1776     protected function create_single_discussion_with_replies($forum, $user, $replycount) {
1777         global $DB;
1779         $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1781         $record = new stdClass();
1782         $record->course = $forum->course;
1783         $record->forum = $forum->id;
1784         $record->userid = $user->id;
1785         $discussion = $generator->create_discussion($record);
1787         // Retrieve the first post.
1788         $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1790         // Create the replies.
1791         $post = new stdClass();
1792         $post->userid = $user->id;
1793         $post->discussion = $discussion->id;
1794         $post->parent = $replyto->id;
1796         for ($i = 0; $i < $replycount; $i++) {
1797             $generator->create_post($post);
1798         }
1800         return $discussion;
1801     }
1803     /**
1804      * Tests for mod_forum_rating_can_see_item_ratings().
1805      *
1806      * @throws coding_exception
1807      * @throws rating_exception
1808      */
1809     public function test_mod_forum_rating_can_see_item_ratings() {
1810         global $DB;
1812         $this->resetAfterTest();
1814         // Setup test data.
1815         $course = new stdClass();
1816         $course->groupmode = SEPARATEGROUPS;
1817         $course->groupmodeforce = true;
1818         $course = $this->getDataGenerator()->create_course($course);
1819         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1820         $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1821         $cm = get_coursemodule_from_instance('forum', $forum->id);
1822         $context = context_module::instance($cm->id);
1824         // Create users.
1825         $user1 = $this->getDataGenerator()->create_user();
1826         $user2 = $this->getDataGenerator()->create_user();
1827         $user3 = $this->getDataGenerator()->create_user();
1828         $user4 = $this->getDataGenerator()->create_user();
1830         // Groups and stuff.
1831         $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
1832         $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id);
1833         $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id);
1834         $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id);
1835         $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id);
1837         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1838         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1839         groups_add_member($group1, $user1);
1840         groups_add_member($group1, $user2);
1841         groups_add_member($group2, $user3);
1842         groups_add_member($group2, $user4);
1844         $record = new stdClass();
1845         $record->course = $forum->course;
1846         $record->forum = $forum->id;
1847         $record->userid = $user1->id;
1848         $record->groupid = $group1->id;
1849         $discussion = $generator->create_discussion($record);
1851         // Retrieve the first post.
1852         $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1854         $ratingoptions = new stdClass;
1855         $ratingoptions->context = $context;
1856         $ratingoptions->ratingarea = 'post';
1857         $ratingoptions->component = 'mod_forum';
1858         $ratingoptions->itemid  = $post->id;
1859         $ratingoptions->scaleid = 2;
1860         $ratingoptions->userid  = $user2->id;
1861         $rating = new rating($ratingoptions);
1862         $rating->update_rating(2);
1864         // Now try to access it as various users.
1865         unassign_capability('moodle/site:accessallgroups', $role->id);
1866         $params = array('contextid' => 2,
1867                         'component' => 'mod_forum',
1868                         'ratingarea' => 'post',
1869                         'itemid' => $post->id,
1870                         'scaleid' => 2);
1871         $this->setUser($user1);
1872         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1873         $this->setUser($user2);
1874         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1875         $this->setUser($user3);
1876         $this->assertFalse(mod_forum_rating_can_see_item_ratings($params));
1877         $this->setUser($user4);
1878         $this->assertFalse(mod_forum_rating_can_see_item_ratings($params));
1880         // Now try with accessallgroups cap and make sure everything is visible.
1881         assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id);
1882         $this->setUser($user1);
1883         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1884         $this->setUser($user2);
1885         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1886         $this->setUser($user3);
1887         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1888         $this->setUser($user4);
1889         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1891         // Change group mode and verify visibility.
1892         $course->groupmode = VISIBLEGROUPS;
1893         $DB->update_record('course', $course);
1894         unassign_capability('moodle/site:accessallgroups', $role->id);
1895         $this->setUser($user1);
1896         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1897         $this->setUser($user2);
1898         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1899         $this->setUser($user3);
1900         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1901         $this->setUser($user4);
1902         $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1904     }
1906     /**
1907      * Test forum_get_discussions
1908      */
1909     public function test_forum_get_discussions_with_groups() {
1910         global $DB;
1912         $this->resetAfterTest(true);
1914         // Create course to add the module.
1915         $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
1916         $user1 = self::getDataGenerator()->create_user();
1917         $user2 = self::getDataGenerator()->create_user();
1918         $user3 = self::getDataGenerator()->create_user();
1920         $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
1921         self::getDataGenerator()->enrol_user($user1->id, $course->id, $role->id);
1922         self::getDataGenerator()->enrol_user($user2->id, $course->id, $role->id);
1923         self::getDataGenerator()->enrol_user($user3->id, $course->id, $role->id);
1925         // Forum forcing separate gropus.
1926         $record = new stdClass();
1927         $record->course = $course->id;
1928         $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
1929         $cm = get_coursemodule_from_instance('forum', $forum->id);
1931         // Create groups.
1932         $group1 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
1933         $group2 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
1934         $group3 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
1936         // Add the user1 to g1 and g2 groups.
1937         groups_add_member($group1->id, $user1->id);
1938         groups_add_member($group2->id, $user1->id);
1940         // Add the user 2 and 3 to only one group.
1941         groups_add_member($group1->id, $user2->id);
1942         groups_add_member($group3->id, $user3->id);
1944         // Add a few discussions.
1945         $record = array();
1946         $record['course'] = $course->id;
1947         $record['forum'] = $forum->id;
1948         $record['userid'] = $user1->id;
1949         $record['groupid'] = $group1->id;
1950         $discussiong1u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1952         $record['groupid'] = $group2->id;
1953         $discussiong2u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1955         $record['userid'] = $user2->id;
1956         $record['groupid'] = $group1->id;
1957         $discussiong1u2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1959         $record['userid'] = $user3->id;
1960         $record['groupid'] = $group3->id;
1961         $discussiong3u3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
1963         self::setUser($user1);
1964         // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions.
1965         $discussions = forum_get_discussions($cm);
1966         self::assertCount(2, $discussions);
1967         foreach ($discussions as $discussion) {
1968             self::assertEquals($group1->id, $discussion->groupid);
1969         }
1971         // Get all my discussions.
1972         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0);
1973         self::assertCount(3, $discussions);
1975         // Get all my g1 discussions.
1976         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group1->id);
1977         self::assertCount(2, $discussions);
1978         foreach ($discussions as $discussion) {
1979             self::assertEquals($group1->id, $discussion->groupid);
1980         }
1982         // Get all my g2 discussions.
1983         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id);
1984         self::assertCount(1, $discussions);
1985         $discussion = array_shift($discussions);
1986         self::assertEquals($group2->id, $discussion->groupid);
1987         self::assertEquals($user1->id, $discussion->userid);
1988         self::assertEquals($discussiong2u1->id, $discussion->discussion);
1990         // Get all my g3 discussions (I'm not enrolled in that group).
1991         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id);
1992         self::assertCount(0, $discussions);
1994         // This group does not exist.
1995         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id + 1000);
1996         self::assertCount(0, $discussions);
1998         self::setUser($user2);
2000         // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions.
2001         $discussions = forum_get_discussions($cm);
2002         self::assertCount(2, $discussions);
2003         foreach ($discussions as $discussion) {
2004             self::assertEquals($group1->id, $discussion->groupid);
2005         }
2007         // Get all my viewable discussions.
2008         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0);
2009         self::assertCount(2, $discussions);
2010         foreach ($discussions as $discussion) {
2011             self::assertEquals($group1->id, $discussion->groupid);
2012         }
2014         // Get all my g2 discussions (I'm not enrolled in that group).
2015         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id);
2016         self::assertCount(0, $discussions);
2018         // Get all my g3 discussions (I'm not enrolled in that group).
2019         $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id);
2020         self::assertCount(0, $discussions);
2022     }
2024     /**
2025      * Test forum_user_can_post_discussion
2026      */
2027     public function test_forum_user_can_post_discussion() {
2028         global $CFG, $DB;
2030         $this->resetAfterTest(true);
2032         // Create course to add the module.
2033         $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1));
2034         $user = self::getDataGenerator()->create_user();
2035         $this->getDataGenerator()->enrol_user($user->id, $course->id);
2037         // Forum forcing separate gropus.
2038         $record = new stdClass();
2039         $record->course = $course->id;
2040         $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
2041         $cm = get_coursemodule_from_instance('forum', $forum->id);
2042         $context = context_module::instance($cm->id);
2044         self::setUser($user);
2046         // The user is not enroled in any group, try to post in a forum with separate groups.
2047         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2048         $this->assertFalse($can);
2050         // Create a group.
2051         $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2053         // Try to post in a group the user is not enrolled.
2054         $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context);
2055         $this->assertFalse($can);
2057         // Add the user to a group.
2058         groups_add_member($group->id, $user->id);
2060         // Try to post in a group the user is not enrolled.
2061         $can = forum_user_can_post_discussion($forum, $group->id + 1, -1, $cm, $context);
2062         $this->assertFalse($can);
2064         // Now try to post in the user group. (null means it will guess the group).
2065         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2066         $this->assertTrue($can);
2068         $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context);
2069         $this->assertTrue($can);
2071         // Test all groups.
2072         $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context);
2073         $this->assertFalse($can);
2075         $this->setAdminUser();
2076         $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context);
2077         $this->assertTrue($can);
2079         // Change forum type.
2080         $forum->type = 'news';
2081         $DB->update_record('forum', $forum);
2083         // Admin can post news.
2084         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2085         $this->assertTrue($can);
2087         // Normal users don't.
2088         self::setUser($user);
2089         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2090         $this->assertFalse($can);
2092         // Change forum type.
2093         $forum->type = 'eachuser';
2094         $DB->update_record('forum', $forum);
2096         // I didn't post yet, so I should be able to post.
2097         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2098         $this->assertTrue($can);
2100         // Post now.
2101         $record = new stdClass();
2102         $record->course = $course->id;
2103         $record->userid = $user->id;
2104         $record->forum = $forum->id;
2105         $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2107         // I already posted, I shouldn't be able to post.
2108         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2109         $this->assertFalse($can);
2111         // Last check with no groups, normal forum and course.
2112         $course->groupmode = NOGROUPS;
2113         $course->groupmodeforce = 0;
2114         $DB->update_record('course', $course);
2116         $forum->type = 'general';
2117         $forum->groupmode = NOGROUPS;
2118         $DB->update_record('forum', $forum);
2120         $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2121         $this->assertTrue($can);
2122     }