19419b79377e46494597c5d96bb913f78c3ecaef
[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');
30 class mod_forum_lib_testcase extends advanced_testcase {
32     public function setUp() {
33         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
34         // tests using these functions.
35         \mod_forum\subscriptions::reset_forum_cache();
36     }
38     public function tearDown() {
39         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
40         // tests using these functions.
41         \mod_forum\subscriptions::reset_forum_cache();
42     }
44     public function test_forum_trigger_content_uploaded_event() {
45         $this->resetAfterTest();
47         $user = $this->getDataGenerator()->create_user();
48         $course = $this->getDataGenerator()->create_course();
49         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
50         $context = context_module::instance($forum->cmid);
52         $this->setUser($user->id);
53         $fakepost = (object) array('id' => 123, 'message' => 'Yay!', 'discussion' => 100);
54         $cm = get_coursemodule_from_instance('forum', $forum->id);
56         $fs = get_file_storage();
57         $dummy = (object) array(
58             'contextid' => $context->id,
59             'component' => 'mod_forum',
60             'filearea' => 'attachment',
61             'itemid' => $fakepost->id,
62             'filepath' => '/',
63             'filename' => 'myassignmnent.pdf'
64         );
65         $fi = $fs->create_file_from_string($dummy, 'Content of ' . $dummy->filename);
67         $data = new stdClass();
68         $sink = $this->redirectEvents();
69         forum_trigger_content_uploaded_event($fakepost, $cm, 'some triggered from value');
70         $events = $sink->get_events();
72         $this->assertCount(1, $events);
73         $event = reset($events);
74         $this->assertInstanceOf('\mod_forum\event\assessable_uploaded', $event);
75         $this->assertEquals($context->id, $event->contextid);
76         $this->assertEquals($fakepost->id, $event->objectid);
77         $this->assertEquals($fakepost->message, $event->other['content']);
78         $this->assertEquals($fakepost->discussion, $event->other['discussionid']);
79         $this->assertCount(1, $event->other['pathnamehashes']);
80         $this->assertEquals($fi->get_pathnamehash(), $event->other['pathnamehashes'][0]);
81         $expected = new stdClass();
82         $expected->modulename = 'forum';
83         $expected->name = 'some triggered from value';
84         $expected->cmid = $forum->cmid;
85         $expected->itemid = $fakepost->id;
86         $expected->courseid = $course->id;
87         $expected->userid = $user->id;
88         $expected->content = $fakepost->message;
89         $expected->pathnamehashes = array($fi->get_pathnamehash());
90         $this->assertEventLegacyData($expected, $event);
91         $this->assertEventContextNotUsed($event);
92     }
94     public function test_forum_get_courses_user_posted_in() {
95         $this->resetAfterTest();
97         $user1 = $this->getDataGenerator()->create_user();
98         $user2 = $this->getDataGenerator()->create_user();
99         $user3 = $this->getDataGenerator()->create_user();
101         $course1 = $this->getDataGenerator()->create_course();
102         $course2 = $this->getDataGenerator()->create_course();
103         $course3 = $this->getDataGenerator()->create_course();
105         // Create 3 forums, one in each course.
106         $record = new stdClass();
107         $record->course = $course1->id;
108         $forum1 = $this->getDataGenerator()->create_module('forum', $record);
110         $record = new stdClass();
111         $record->course = $course2->id;
112         $forum2 = $this->getDataGenerator()->create_module('forum', $record);
114         $record = new stdClass();
115         $record->course = $course3->id;
116         $forum3 = $this->getDataGenerator()->create_module('forum', $record);
118         // Add a second forum in course 1.
119         $record = new stdClass();
120         $record->course = $course1->id;
121         $forum4 = $this->getDataGenerator()->create_module('forum', $record);
123         // Add discussions to course 1 started by user1.
124         $record = new stdClass();
125         $record->course = $course1->id;
126         $record->userid = $user1->id;
127         $record->forum = $forum1->id;
128         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
130         $record = new stdClass();
131         $record->course = $course1->id;
132         $record->userid = $user1->id;
133         $record->forum = $forum4->id;
134         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
136         // Add discussions to course2 started by user1.
137         $record = new stdClass();
138         $record->course = $course2->id;
139         $record->userid = $user1->id;
140         $record->forum = $forum2->id;
141         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
143         // Add discussions to course 3 started by user2.
144         $record = new stdClass();
145         $record->course = $course3->id;
146         $record->userid = $user2->id;
147         $record->forum = $forum3->id;
148         $discussion3 = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
150         // Add post to course 3 by user1.
151         $record = new stdClass();
152         $record->course = $course3->id;
153         $record->userid = $user1->id;
154         $record->forum = $forum3->id;
155         $record->discussion = $discussion3->id;
156         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
158         // User 3 hasn't posted anything, so shouldn't get any results.
159         $user3courses = forum_get_courses_user_posted_in($user3);
160         $this->assertEmpty($user3courses);
162         // User 2 has only posted in course3.
163         $user2courses = forum_get_courses_user_posted_in($user2);
164         $this->assertCount(1, $user2courses);
165         $user2course = array_shift($user2courses);
166         $this->assertEquals($course3->id, $user2course->id);
167         $this->assertEquals($course3->shortname, $user2course->shortname);
169         // User 1 has posted in all 3 courses.
170         $user1courses = forum_get_courses_user_posted_in($user1);
171         $this->assertCount(3, $user1courses);
172         foreach ($user1courses as $course) {
173             $this->assertContains($course->id, array($course1->id, $course2->id, $course3->id));
174             $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname,
175                 $course3->shortname));
177         }
179         // User 1 has only started a discussion in course 1 and 2 though.
180         $user1courses = forum_get_courses_user_posted_in($user1, true);
181         $this->assertCount(2, $user1courses);
182         foreach ($user1courses as $course) {
183             $this->assertContains($course->id, array($course1->id, $course2->id));
184             $this->assertContains($course->shortname, array($course1->shortname, $course2->shortname));
185         }
186     }
188     /**
189      * Test the logic in the forum_tp_can_track_forums() function.
190      */
191     public function test_forum_tp_can_track_forums() {
192         global $CFG;
194         $this->resetAfterTest();
196         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
197         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
198         $course = $this->getDataGenerator()->create_course();
199         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
200         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
202         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
203         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
205         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
206         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
208         // Allow force.
209         $CFG->forum_allowforcedreadtracking = 1;
211         // User on, forum off, should be off.
212         $result = forum_tp_can_track_forums($forumoff, $useron);
213         $this->assertEquals(false, $result);
215         // User on, forum on, should be on.
216         $result = forum_tp_can_track_forums($forumforce, $useron);
217         $this->assertEquals(true, $result);
219         // User on, forum optional, should be on.
220         $result = forum_tp_can_track_forums($forumoptional, $useron);
221         $this->assertEquals(true, $result);
223         // User off, forum off, should be off.
224         $result = forum_tp_can_track_forums($forumoff, $useroff);
225         $this->assertEquals(false, $result);
227         // User off, forum force, should be on.
228         $result = forum_tp_can_track_forums($forumforce, $useroff);
229         $this->assertEquals(true, $result);
231         // User off, forum optional, should be off.
232         $result = forum_tp_can_track_forums($forumoptional, $useroff);
233         $this->assertEquals(false, $result);
235         // Don't allow force.
236         $CFG->forum_allowforcedreadtracking = 0;
238         // User on, forum off, should be off.
239         $result = forum_tp_can_track_forums($forumoff, $useron);
240         $this->assertEquals(false, $result);
242         // User on, forum on, should be on.
243         $result = forum_tp_can_track_forums($forumforce, $useron);
244         $this->assertEquals(true, $result);
246         // User on, forum optional, should be on.
247         $result = forum_tp_can_track_forums($forumoptional, $useron);
248         $this->assertEquals(true, $result);
250         // User off, forum off, should be off.
251         $result = forum_tp_can_track_forums($forumoff, $useroff);
252         $this->assertEquals(false, $result);
254         // User off, forum force, should be off.
255         $result = forum_tp_can_track_forums($forumforce, $useroff);
256         $this->assertEquals(false, $result);
258         // User off, forum optional, should be off.
259         $result = forum_tp_can_track_forums($forumoptional, $useroff);
260         $this->assertEquals(false, $result);
262     }
264     /**
265      * Test the logic in the test_forum_tp_is_tracked() function.
266      */
267     public function test_forum_tp_is_tracked() {
268         global $CFG;
270         $this->resetAfterTest();
272         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
273         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
274         $course = $this->getDataGenerator()->create_course();
275         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
276         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
278         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
279         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
281         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
282         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
284         // Allow force.
285         $CFG->forum_allowforcedreadtracking = 1;
287         // User on, forum off, should be off.
288         $result = forum_tp_is_tracked($forumoff, $useron);
289         $this->assertEquals(false, $result);
291         // User on, forum force, should be on.
292         $result = forum_tp_is_tracked($forumforce, $useron);
293         $this->assertEquals(true, $result);
295         // User on, forum optional, should be on.
296         $result = forum_tp_is_tracked($forumoptional, $useron);
297         $this->assertEquals(true, $result);
299         // User off, forum off, should be off.
300         $result = forum_tp_is_tracked($forumoff, $useroff);
301         $this->assertEquals(false, $result);
303         // User off, forum force, should be on.
304         $result = forum_tp_is_tracked($forumforce, $useroff);
305         $this->assertEquals(true, $result);
307         // User off, forum optional, should be off.
308         $result = forum_tp_is_tracked($forumoptional, $useroff);
309         $this->assertEquals(false, $result);
311         // Don't allow force.
312         $CFG->forum_allowforcedreadtracking = 0;
314         // User on, forum off, should be off.
315         $result = forum_tp_is_tracked($forumoff, $useron);
316         $this->assertEquals(false, $result);
318         // User on, forum force, should be on.
319         $result = forum_tp_is_tracked($forumforce, $useron);
320         $this->assertEquals(true, $result);
322         // User on, forum optional, should be on.
323         $result = forum_tp_is_tracked($forumoptional, $useron);
324         $this->assertEquals(true, $result);
326         // User off, forum off, should be off.
327         $result = forum_tp_is_tracked($forumoff, $useroff);
328         $this->assertEquals(false, $result);
330         // User off, forum force, should be off.
331         $result = forum_tp_is_tracked($forumforce, $useroff);
332         $this->assertEquals(false, $result);
334         // User off, forum optional, should be off.
335         $result = forum_tp_is_tracked($forumoptional, $useroff);
336         $this->assertEquals(false, $result);
338         // Stop tracking so we can test again.
339         forum_tp_stop_tracking($forumforce->id, $useron->id);
340         forum_tp_stop_tracking($forumoptional->id, $useron->id);
341         forum_tp_stop_tracking($forumforce->id, $useroff->id);
342         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
344         // Allow force.
345         $CFG->forum_allowforcedreadtracking = 1;
347         // User on, preference off, forum force, should be on.
348         $result = forum_tp_is_tracked($forumforce, $useron);
349         $this->assertEquals(true, $result);
351         // User on, preference off, forum optional, should be on.
352         $result = forum_tp_is_tracked($forumoptional, $useron);
353         $this->assertEquals(false, $result);
355         // User off, preference off, forum force, should be on.
356         $result = forum_tp_is_tracked($forumforce, $useroff);
357         $this->assertEquals(true, $result);
359         // User off, preference off, forum optional, should be off.
360         $result = forum_tp_is_tracked($forumoptional, $useroff);
361         $this->assertEquals(false, $result);
363         // Don't allow force.
364         $CFG->forum_allowforcedreadtracking = 0;
366         // User on, preference off, forum force, should be on.
367         $result = forum_tp_is_tracked($forumforce, $useron);
368         $this->assertEquals(false, $result);
370         // User on, preference off, forum optional, should be on.
371         $result = forum_tp_is_tracked($forumoptional, $useron);
372         $this->assertEquals(false, $result);
374         // User off, preference off, forum force, should be off.
375         $result = forum_tp_is_tracked($forumforce, $useroff);
376         $this->assertEquals(false, $result);
378         // User off, preference off, forum optional, should be off.
379         $result = forum_tp_is_tracked($forumoptional, $useroff);
380         $this->assertEquals(false, $result);
381     }
383     /**
384      * Test the logic in the forum_tp_get_course_unread_posts() function.
385      */
386     public function test_forum_tp_get_course_unread_posts() {
387         global $CFG;
389         $this->resetAfterTest();
391         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
392         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
393         $course = $this->getDataGenerator()->create_course();
394         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
395         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
397         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
398         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
400         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
401         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
403         // Add discussions to the tracking off forum.
404         $record = new stdClass();
405         $record->course = $course->id;
406         $record->userid = $useron->id;
407         $record->forum = $forumoff->id;
408         $discussionoff = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
410         // Add discussions to the tracking forced forum.
411         $record = new stdClass();
412         $record->course = $course->id;
413         $record->userid = $useron->id;
414         $record->forum = $forumforce->id;
415         $discussionforce = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
417         // Add post to the tracking forced discussion.
418         $record = new stdClass();
419         $record->course = $course->id;
420         $record->userid = $useroff->id;
421         $record->forum = $forumforce->id;
422         $record->discussion = $discussionforce->id;
423         $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record);
425         // Add discussions to the tracking optional forum.
426         $record = new stdClass();
427         $record->course = $course->id;
428         $record->userid = $useron->id;
429         $record->forum = $forumoptional->id;
430         $discussionoptional = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
432         // Allow force.
433         $CFG->forum_allowforcedreadtracking = 1;
435         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
436         $this->assertEquals(2, count($result));
437         $this->assertEquals(false, isset($result[$forumoff->id]));
438         $this->assertEquals(true, isset($result[$forumforce->id]));
439         $this->assertEquals(2, $result[$forumforce->id]->unread);
440         $this->assertEquals(true, isset($result[$forumoptional->id]));
441         $this->assertEquals(1, $result[$forumoptional->id]->unread);
443         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
444         $this->assertEquals(1, count($result));
445         $this->assertEquals(false, isset($result[$forumoff->id]));
446         $this->assertEquals(true, isset($result[$forumforce->id]));
447         $this->assertEquals(2, $result[$forumforce->id]->unread);
448         $this->assertEquals(false, isset($result[$forumoptional->id]));
450         // Don't allow force.
451         $CFG->forum_allowforcedreadtracking = 0;
453         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
454         $this->assertEquals(2, count($result));
455         $this->assertEquals(false, isset($result[$forumoff->id]));
456         $this->assertEquals(true, isset($result[$forumforce->id]));
457         $this->assertEquals(2, $result[$forumforce->id]->unread);
458         $this->assertEquals(true, isset($result[$forumoptional->id]));
459         $this->assertEquals(1, $result[$forumoptional->id]->unread);
461         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
462         $this->assertEquals(0, count($result));
463         $this->assertEquals(false, isset($result[$forumoff->id]));
464         $this->assertEquals(false, isset($result[$forumforce->id]));
465         $this->assertEquals(false, isset($result[$forumoptional->id]));
467         // Stop tracking so we can test again.
468         forum_tp_stop_tracking($forumforce->id, $useron->id);
469         forum_tp_stop_tracking($forumoptional->id, $useron->id);
470         forum_tp_stop_tracking($forumforce->id, $useroff->id);
471         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
473         // Allow force.
474         $CFG->forum_allowforcedreadtracking = 1;
476         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
477         $this->assertEquals(1, count($result));
478         $this->assertEquals(false, isset($result[$forumoff->id]));
479         $this->assertEquals(true, isset($result[$forumforce->id]));
480         $this->assertEquals(2, $result[$forumforce->id]->unread);
481         $this->assertEquals(false, isset($result[$forumoptional->id]));
483         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
484         $this->assertEquals(1, count($result));
485         $this->assertEquals(false, isset($result[$forumoff->id]));
486         $this->assertEquals(true, isset($result[$forumforce->id]));
487         $this->assertEquals(2, $result[$forumforce->id]->unread);
488         $this->assertEquals(false, isset($result[$forumoptional->id]));
490         // Don't allow force.
491         $CFG->forum_allowforcedreadtracking = 0;
493         $result = forum_tp_get_course_unread_posts($useron->id, $course->id);
494         $this->assertEquals(0, count($result));
495         $this->assertEquals(false, isset($result[$forumoff->id]));
496         $this->assertEquals(false, isset($result[$forumforce->id]));
497         $this->assertEquals(false, isset($result[$forumoptional->id]));
499         $result = forum_tp_get_course_unread_posts($useroff->id, $course->id);
500         $this->assertEquals(0, count($result));
501         $this->assertEquals(false, isset($result[$forumoff->id]));
502         $this->assertEquals(false, isset($result[$forumforce->id]));
503         $this->assertEquals(false, isset($result[$forumoptional->id]));
504     }
506     /**
507      * Test the logic in the test_forum_tp_get_untracked_forums() function.
508      */
509     public function test_forum_tp_get_untracked_forums() {
510         global $CFG;
512         $this->resetAfterTest();
514         $useron = $this->getDataGenerator()->create_user(array('trackforums' => 1));
515         $useroff = $this->getDataGenerator()->create_user(array('trackforums' => 0));
516         $course = $this->getDataGenerator()->create_course();
517         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OFF); // Off.
518         $forumoff = $this->getDataGenerator()->create_module('forum', $options);
520         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
521         $forumforce = $this->getDataGenerator()->create_module('forum', $options);
523         $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
524         $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
526         // Allow force.
527         $CFG->forum_allowforcedreadtracking = 1;
529         // On user with force on.
530         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
531         $this->assertEquals(1, count($result));
532         $this->assertEquals(true, isset($result[$forumoff->id]));
534         // Off user with force on.
535         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
536         $this->assertEquals(2, count($result));
537         $this->assertEquals(true, isset($result[$forumoff->id]));
538         $this->assertEquals(true, isset($result[$forumoptional->id]));
540         // Don't allow force.
541         $CFG->forum_allowforcedreadtracking = 0;
543         // On user with force off.
544         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
545         $this->assertEquals(1, count($result));
546         $this->assertEquals(true, isset($result[$forumoff->id]));
548         // Off user with force off.
549         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
550         $this->assertEquals(3, count($result));
551         $this->assertEquals(true, isset($result[$forumoff->id]));
552         $this->assertEquals(true, isset($result[$forumoptional->id]));
553         $this->assertEquals(true, isset($result[$forumforce->id]));
555         // Stop tracking so we can test again.
556         forum_tp_stop_tracking($forumforce->id, $useron->id);
557         forum_tp_stop_tracking($forumoptional->id, $useron->id);
558         forum_tp_stop_tracking($forumforce->id, $useroff->id);
559         forum_tp_stop_tracking($forumoptional->id, $useroff->id);
561         // Allow force.
562         $CFG->forum_allowforcedreadtracking = 1;
564         // On user with force on.
565         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
566         $this->assertEquals(2, count($result));
567         $this->assertEquals(true, isset($result[$forumoff->id]));
568         $this->assertEquals(true, isset($result[$forumoptional->id]));
570         // Off user with force on.
571         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
572         $this->assertEquals(2, count($result));
573         $this->assertEquals(true, isset($result[$forumoff->id]));
574         $this->assertEquals(true, isset($result[$forumoptional->id]));
576         // Don't allow force.
577         $CFG->forum_allowforcedreadtracking = 0;
579         // On user with force off.
580         $result = forum_tp_get_untracked_forums($useron->id, $course->id);
581         $this->assertEquals(3, count($result));
582         $this->assertEquals(true, isset($result[$forumoff->id]));
583         $this->assertEquals(true, isset($result[$forumoptional->id]));
584         $this->assertEquals(true, isset($result[$forumforce->id]));
586         // Off user with force off.
587         $result = forum_tp_get_untracked_forums($useroff->id, $course->id);
588         $this->assertEquals(3, count($result));
589         $this->assertEquals(true, isset($result[$forumoff->id]));
590         $this->assertEquals(true, isset($result[$forumoptional->id]));
591         $this->assertEquals(true, isset($result[$forumforce->id]));
592     }
594     /**
595      * Test subscription using automatic subscription on create.
596      */
597     public function test_forum_auto_subscribe_on_create() {
598         global $CFG;
600         $this->resetAfterTest();
602         $usercount = 5;
603         $course = $this->getDataGenerator()->create_course();
604         $users = array();
606         for ($i = 0; $i < $usercount; $i++) {
607             $user = $this->getDataGenerator()->create_user();
608             $users[] = $user;
609             $this->getDataGenerator()->enrol_user($user->id, $course->id);
610         }
612         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); // Automatic Subscription.
613         $forum = $this->getDataGenerator()->create_module('forum', $options);
615         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
616         $this->assertEquals($usercount, count($result));
617         foreach ($users as $user) {
618             $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
619         }
620     }
622     /**
623      * Test subscription using forced subscription on create.
624      */
625     public function test_forum_forced_subscribe_on_create() {
626         global $CFG;
628         $this->resetAfterTest();
630         $usercount = 5;
631         $course = $this->getDataGenerator()->create_course();
632         $users = array();
634         for ($i = 0; $i < $usercount; $i++) {
635             $user = $this->getDataGenerator()->create_user();
636             $users[] = $user;
637             $this->getDataGenerator()->enrol_user($user->id, $course->id);
638         }
640         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); // Forced subscription.
641         $forum = $this->getDataGenerator()->create_module('forum', $options);
643         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
644         $this->assertEquals($usercount, count($result));
645         foreach ($users as $user) {
646             $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
647         }
648     }
650     /**
651      * Test subscription using optional subscription on create.
652      */
653     public function test_forum_optional_subscribe_on_create() {
654         global $CFG;
656         $this->resetAfterTest();
658         $usercount = 5;
659         $course = $this->getDataGenerator()->create_course();
660         $users = array();
662         for ($i = 0; $i < $usercount; $i++) {
663             $user = $this->getDataGenerator()->create_user();
664             $users[] = $user;
665             $this->getDataGenerator()->enrol_user($user->id, $course->id);
666         }
668         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); // Subscription optional.
669         $forum = $this->getDataGenerator()->create_module('forum', $options);
671         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
672         // No subscriptions by default.
673         $this->assertEquals(0, count($result));
674         foreach ($users as $user) {
675             $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
676         }
677     }
679     /**
680      * Test subscription using disallow subscription on create.
681      */
682     public function test_forum_disallow_subscribe_on_create() {
683         global $CFG;
685         $this->resetAfterTest();
687         $usercount = 5;
688         $course = $this->getDataGenerator()->create_course();
689         $users = array();
691         for ($i = 0; $i < $usercount; $i++) {
692             $user = $this->getDataGenerator()->create_user();
693             $users[] = $user;
694             $this->getDataGenerator()->enrol_user($user->id, $course->id);
695         }
697         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); // Subscription prevented.
698         $forum = $this->getDataGenerator()->create_module('forum', $options);
700         $result = \mod_forum\subscriptions::fetch_subscribed_users($forum);
701         // No subscriptions by default.
702         $this->assertEquals(0, count($result));
703         foreach ($users as $user) {
704             $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
705         }
706     }
708     /**
709      * Test that context fetching returns the appropriate context.
710      */
711     public function test_forum_get_context() {
712         global $DB, $PAGE;
714         $this->resetAfterTest();
716         // Setup test data.
717         $course = $this->getDataGenerator()->create_course();
718         $coursecontext = \context_course::instance($course->id);
720         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
721         $forum = $this->getDataGenerator()->create_module('forum', $options);
722         $forumcm = get_coursemodule_from_instance('forum', $forum->id);
723         $forumcontext = \context_module::instance($forumcm->id);
725         // First check that specifying the context results in the correct context being returned.
726         // Do this before we set up the page object and we should return from the coursemodule record.
727         // There should be no DB queries here because the context type was correct.
728         $startcount = $DB->perf_get_reads();
729         $result = forum_get_context($forum->id, $forumcontext);
730         $aftercount = $DB->perf_get_reads();
731         $this->assertEquals($forumcontext, $result);
732         $this->assertEquals(0, $aftercount - $startcount);
734         // And a context which is not the correct type.
735         // This tests will result in a DB query to fetch the course_module.
736         $startcount = $DB->perf_get_reads();
737         $result = forum_get_context($forum->id, $coursecontext);
738         $aftercount = $DB->perf_get_reads();
739         $this->assertEquals($forumcontext, $result);
740         $this->assertEquals(1, $aftercount - $startcount);
742         // Now do not specify a context at all.
743         // This tests will result in a DB query to fetch the course_module.
744         $startcount = $DB->perf_get_reads();
745         $result = forum_get_context($forum->id);
746         $aftercount = $DB->perf_get_reads();
747         $this->assertEquals($forumcontext, $result);
748         $this->assertEquals(1, $aftercount - $startcount);
750         // Set up the default page event to use the forum.
751         $PAGE = new moodle_page();
752         $PAGE->set_context($forumcontext);
753         $PAGE->set_cm($forumcm, $course, $forum);
755         // Now specify a context which is not a context_module.
756         // There should be no DB queries here because we use the PAGE.
757         $startcount = $DB->perf_get_reads();
758         $result = forum_get_context($forum->id, $coursecontext);
759         $aftercount = $DB->perf_get_reads();
760         $this->assertEquals($forumcontext, $result);
761         $this->assertEquals(0, $aftercount - $startcount);
763         // Now do not specify a context at all.
764         // There should be no DB queries here because we use the PAGE.
765         $startcount = $DB->perf_get_reads();
766         $result = forum_get_context($forum->id);
767         $aftercount = $DB->perf_get_reads();
768         $this->assertEquals($forumcontext, $result);
769         $this->assertEquals(0, $aftercount - $startcount);
771         // Now specify the page context of the course instead..
772         $PAGE = new moodle_page();
773         $PAGE->set_context($coursecontext);
775         // Now specify a context which is not a context_module.
776         // This tests will result in a DB query to fetch the course_module.
777         $startcount = $DB->perf_get_reads();
778         $result = forum_get_context($forum->id, $coursecontext);
779         $aftercount = $DB->perf_get_reads();
780         $this->assertEquals($forumcontext, $result);
781         $this->assertEquals(1, $aftercount - $startcount);
783         // Now do not specify a context at all.
784         // This tests will result in a DB query to fetch the course_module.
785         $startcount = $DB->perf_get_reads();
786         $result = forum_get_context($forum->id);
787         $aftercount = $DB->perf_get_reads();
788         $this->assertEquals($forumcontext, $result);
789         $this->assertEquals(1, $aftercount - $startcount);
790     }
792     /**
793      * Test getting the neighbour threads of a discussion.
794      */
795     public function test_forum_get_neighbours() {
796         global $CFG, $DB;
797         $this->resetAfterTest();
799         // Setup test data.
800         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
801         $course = $this->getDataGenerator()->create_course();
802         $user = $this->getDataGenerator()->create_user();
803         $user2 = $this->getDataGenerator()->create_user();
805         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
806         $cm = get_coursemodule_from_instance('forum', $forum->id);
807         $context = context_module::instance($cm->id);
809         $record = new stdClass();
810         $record->course = $course->id;
811         $record->userid = $user->id;
812         $record->forum = $forum->id;
813         $disc1 = $forumgen->create_discussion($record);
814         sleep(1);
815         $disc2 = $forumgen->create_discussion($record);
816         sleep(1);
817         $disc3 = $forumgen->create_discussion($record);
818         sleep(1);
819         $disc4 = $forumgen->create_discussion($record);
820         sleep(1);
821         $disc5 = $forumgen->create_discussion($record);
823         // Getting the neighbours.
824         $neighbours = forum_get_discussion_neighbours($cm, $disc1);
825         $this->assertEmpty($neighbours['prev']);
826         $this->assertEquals($disc2->id, $neighbours['next']->id);
828         $neighbours = forum_get_discussion_neighbours($cm, $disc2);
829         $this->assertEquals($disc1->id, $neighbours['prev']->id);
830         $this->assertEquals($disc3->id, $neighbours['next']->id);
832         $neighbours = forum_get_discussion_neighbours($cm, $disc3);
833         $this->assertEquals($disc2->id, $neighbours['prev']->id);
834         $this->assertEquals($disc4->id, $neighbours['next']->id);
836         $neighbours = forum_get_discussion_neighbours($cm, $disc4);
837         $this->assertEquals($disc3->id, $neighbours['prev']->id);
838         $this->assertEquals($disc5->id, $neighbours['next']->id);
840         $neighbours = forum_get_discussion_neighbours($cm, $disc5);
841         $this->assertEquals($disc4->id, $neighbours['prev']->id);
842         $this->assertEmpty($neighbours['next']);
844         // Post in some discussions. We manually update the discussion record because
845         // the data generator plays with timemodified in a way that would break this test.
846         sleep(1);
847         $disc1->timemodified = time();
848         $DB->update_record('forum_discussions', $disc1);
850         $neighbours = forum_get_discussion_neighbours($cm, $disc5);
851         $this->assertEquals($disc4->id, $neighbours['prev']->id);
852         $this->assertEquals($disc1->id, $neighbours['next']->id);
854         $neighbours = forum_get_discussion_neighbours($cm, $disc2);
855         $this->assertEmpty($neighbours['prev']);
856         $this->assertEquals($disc3->id, $neighbours['next']->id);
858         $neighbours = forum_get_discussion_neighbours($cm, $disc1);
859         $this->assertEquals($disc5->id, $neighbours['prev']->id);
860         $this->assertEmpty($neighbours['next']);
862         // After some discussions were created.
863         sleep(1);
864         $disc6 = $forumgen->create_discussion($record);
865         $neighbours = forum_get_discussion_neighbours($cm, $disc6);
866         $this->assertEquals($disc1->id, $neighbours['prev']->id);
867         $this->assertEmpty($neighbours['next']);
869         sleep(1);
870         $disc7 = $forumgen->create_discussion($record);
871         $neighbours = forum_get_discussion_neighbours($cm, $disc7);
872         $this->assertEquals($disc6->id, $neighbours['prev']->id);
873         $this->assertEmpty($neighbours['next']);
875         // Adding timed discussions.
876         $CFG->forum_enabletimedposts = true;
877         $now = time();
878         $past = $now - 60;
879         $future = $now + 60;
881         $record = new stdClass();
882         $record->course = $course->id;
883         $record->userid = $user->id;
884         $record->forum = $forum->id;
885         $record->timestart = $past;
886         $record->timeend = $future;
887         sleep(1);
888         $disc8 = $forumgen->create_discussion($record);
889         sleep(1);
890         $record->timestart = $future;
891         $record->timeend = 0;
892         $disc9 = $forumgen->create_discussion($record);
893         sleep(1);
894         $record->timestart = 0;
895         $record->timeend = 0;
896         $disc10 = $forumgen->create_discussion($record);
897         sleep(1);
898         $record->timestart = 0;
899         $record->timeend = $past;
900         $disc11 = $forumgen->create_discussion($record);
901         sleep(1);
902         $record->timestart = $past;
903         $record->timeend = $future;
904         $disc12 = $forumgen->create_discussion($record);
906         // Admin user ignores the timed settings of discussions.
907         $this->setAdminUser();
908         $neighbours = forum_get_discussion_neighbours($cm, $disc8);
909         $this->assertEquals($disc7->id, $neighbours['prev']->id);
910         $this->assertEquals($disc9->id, $neighbours['next']->id);
912         $neighbours = forum_get_discussion_neighbours($cm, $disc9);
913         $this->assertEquals($disc8->id, $neighbours['prev']->id);
914         $this->assertEquals($disc10->id, $neighbours['next']->id);
916         $neighbours = forum_get_discussion_neighbours($cm, $disc10);
917         $this->assertEquals($disc9->id, $neighbours['prev']->id);
918         $this->assertEquals($disc11->id, $neighbours['next']->id);
920         $neighbours = forum_get_discussion_neighbours($cm, $disc11);
921         $this->assertEquals($disc10->id, $neighbours['prev']->id);
922         $this->assertEquals($disc12->id, $neighbours['next']->id);
924         $neighbours = forum_get_discussion_neighbours($cm, $disc12);
925         $this->assertEquals($disc11->id, $neighbours['prev']->id);
926         $this->assertEmpty($neighbours['next']);
928         // Normal user can see their own timed discussions.
929         $this->setUser($user);
930         $neighbours = forum_get_discussion_neighbours($cm, $disc8);
931         $this->assertEquals($disc7->id, $neighbours['prev']->id);
932         $this->assertEquals($disc9->id, $neighbours['next']->id);
934         $neighbours = forum_get_discussion_neighbours($cm, $disc9);
935         $this->assertEquals($disc8->id, $neighbours['prev']->id);
936         $this->assertEquals($disc10->id, $neighbours['next']->id);
938         $neighbours = forum_get_discussion_neighbours($cm, $disc10);
939         $this->assertEquals($disc9->id, $neighbours['prev']->id);
940         $this->assertEquals($disc11->id, $neighbours['next']->id);
942         $neighbours = forum_get_discussion_neighbours($cm, $disc11);
943         $this->assertEquals($disc10->id, $neighbours['prev']->id);
944         $this->assertEquals($disc12->id, $neighbours['next']->id);
946         $neighbours = forum_get_discussion_neighbours($cm, $disc12);
947         $this->assertEquals($disc11->id, $neighbours['prev']->id);
948         $this->assertEmpty($neighbours['next']);
950         // Normal user does not ignore timed settings.
951         $this->setUser($user2);
952         $neighbours = forum_get_discussion_neighbours($cm, $disc8);
953         $this->assertEquals($disc7->id, $neighbours['prev']->id);
954         $this->assertEquals($disc10->id, $neighbours['next']->id);
956         $neighbours = forum_get_discussion_neighbours($cm, $disc10);
957         $this->assertEquals($disc8->id, $neighbours['prev']->id);
958         $this->assertEquals($disc12->id, $neighbours['next']->id);
960         $neighbours = forum_get_discussion_neighbours($cm, $disc12);
961         $this->assertEquals($disc10->id, $neighbours['prev']->id);
962         $this->assertEmpty($neighbours['next']);
964         // Reset to normal mode.
965         $CFG->forum_enabletimedposts = false;
966         $this->setAdminUser();
968         // Two discussions with identical timemodified ignore each other.
969         sleep(1);
970         $now = time();
971         $DB->update_record('forum_discussions', (object) array('id' => $disc3->id, 'timemodified' => $now));
972         $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $now));
973         $disc2 = $DB->get_record('forum_discussions', array('id' => $disc2->id));
974         $disc3 = $DB->get_record('forum_discussions', array('id' => $disc3->id));
976         $neighbours = forum_get_discussion_neighbours($cm, $disc2);
977         $this->assertEquals($disc12->id, $neighbours['prev']->id);
978         $this->assertEmpty($neighbours['next']);
980         $neighbours = forum_get_discussion_neighbours($cm, $disc3);
981         $this->assertEquals($disc12->id, $neighbours['prev']->id);
982         $this->assertEmpty($neighbours['next']);
983     }
985     /**
986      * Test getting the neighbour threads of a discussion.
987      */
988     public function test_forum_get_neighbours_with_groups() {
989         $this->resetAfterTest();
991         // Setup test data.
992         $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
993         $course = $this->getDataGenerator()->create_course();
994         $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
995         $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
996         $user1 = $this->getDataGenerator()->create_user();
997         $user2 = $this->getDataGenerator()->create_user();
998         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
999         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
1000         $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id));
1002         $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS));
1003         $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS));
1004         $cm1 = get_coursemodule_from_instance('forum', $forum1->id);
1005         $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
1006         $context1 = context_module::instance($cm1->id);
1007         $context2 = context_module::instance($cm2->id);
1009         // Creating discussions in both forums.
1010         $record = new stdClass();
1011         $record->course = $course->id;
1012         $record->userid = $user1->id;
1013         $record->forum = $forum1->id;
1014         $record->groupid = $group1->id;
1015         $disc11 = $forumgen->create_discussion($record);
1016         $record->forum = $forum2->id;
1017         $disc21 = $forumgen->create_discussion($record);
1019         sleep(1);
1020         $record->userid = $user2->id;
1021         $record->forum = $forum1->id;
1022         $record->groupid = $group2->id;
1023         $disc12 = $forumgen->create_discussion($record);
1024         $record->forum = $forum2->id;
1025         $disc22 = $forumgen->create_discussion($record);
1027         sleep(1);
1028         $record->userid = $user1->id;
1029         $record->forum = $forum1->id;
1030         $record->groupid = null;
1031         $disc13 = $forumgen->create_discussion($record);
1032         $record->forum = $forum2->id;
1033         $disc23 = $forumgen->create_discussion($record);
1035         sleep(1);
1036         $record->userid = $user2->id;
1037         $record->forum = $forum1->id;
1038         $record->groupid = $group2->id;
1039         $disc14 = $forumgen->create_discussion($record);
1040         $record->forum = $forum2->id;
1041         $disc24 = $forumgen->create_discussion($record);
1043         sleep(1);
1044         $record->userid = $user1->id;
1045         $record->forum = $forum1->id;
1046         $record->groupid = $group1->id;
1047         $disc15 = $forumgen->create_discussion($record);
1048         $record->forum = $forum2->id;
1049         $disc25 = $forumgen->create_discussion($record);
1051         // Admin user can see all groups.
1052         $this->setAdminUser();
1053         $neighbours = forum_get_discussion_neighbours($cm1, $disc11);
1054         $this->assertEmpty($neighbours['prev']);
1055         $this->assertEquals($disc12->id, $neighbours['next']->id);
1056         $neighbours = forum_get_discussion_neighbours($cm2, $disc21);
1057         $this->assertEmpty($neighbours['prev']);
1058         $this->assertEquals($disc22->id, $neighbours['next']->id);
1060         $neighbours = forum_get_discussion_neighbours($cm1, $disc12);
1061         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1062         $this->assertEquals($disc13->id, $neighbours['next']->id);
1063         $neighbours = forum_get_discussion_neighbours($cm2, $disc22);
1064         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1065         $this->assertEquals($disc23->id, $neighbours['next']->id);
1067         $neighbours = forum_get_discussion_neighbours($cm1, $disc13);
1068         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1069         $this->assertEquals($disc14->id, $neighbours['next']->id);
1070         $neighbours = forum_get_discussion_neighbours($cm2, $disc23);
1071         $this->assertEquals($disc22->id, $neighbours['prev']->id);
1072         $this->assertEquals($disc24->id, $neighbours['next']->id);
1074         $neighbours = forum_get_discussion_neighbours($cm1, $disc14);
1075         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1076         $this->assertEquals($disc15->id, $neighbours['next']->id);
1077         $neighbours = forum_get_discussion_neighbours($cm2, $disc24);
1078         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1079         $this->assertEquals($disc25->id, $neighbours['next']->id);
1081         $neighbours = forum_get_discussion_neighbours($cm1, $disc15);
1082         $this->assertEquals($disc14->id, $neighbours['prev']->id);
1083         $this->assertEmpty($neighbours['next']);
1084         $neighbours = forum_get_discussion_neighbours($cm2, $disc25);
1085         $this->assertEquals($disc24->id, $neighbours['prev']->id);
1086         $this->assertEmpty($neighbours['next']);
1088         // Admin user is only viewing group 1.
1089         $_POST['group'] = $group1->id;
1090         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1091         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1093         $neighbours = forum_get_discussion_neighbours($cm1, $disc11);
1094         $this->assertEmpty($neighbours['prev']);
1095         $this->assertEquals($disc13->id, $neighbours['next']->id);
1096         $neighbours = forum_get_discussion_neighbours($cm2, $disc21);
1097         $this->assertEmpty($neighbours['prev']);
1098         $this->assertEquals($disc23->id, $neighbours['next']->id);
1100         $neighbours = forum_get_discussion_neighbours($cm1, $disc13);
1101         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1102         $this->assertEquals($disc15->id, $neighbours['next']->id);
1103         $neighbours = forum_get_discussion_neighbours($cm2, $disc23);
1104         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1105         $this->assertEquals($disc25->id, $neighbours['next']->id);
1107         $neighbours = forum_get_discussion_neighbours($cm1, $disc15);
1108         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1109         $this->assertEmpty($neighbours['next']);
1110         $neighbours = forum_get_discussion_neighbours($cm2, $disc25);
1111         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1112         $this->assertEmpty($neighbours['next']);
1114         // Normal user viewing non-grouped posts (this is only possible in visible groups).
1115         $this->setUser($user1);
1116         $_POST['group'] = 0;
1117         $this->assertEquals(0, groups_get_activity_group($cm1, true));
1119         // They can see anything in visible groups.
1120         $neighbours = forum_get_discussion_neighbours($cm1, $disc12);
1121         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1122         $this->assertEquals($disc13->id, $neighbours['next']->id);
1123         $neighbours = forum_get_discussion_neighbours($cm1, $disc13);
1124         $this->assertEquals($disc12->id, $neighbours['prev']->id);
1125         $this->assertEquals($disc14->id, $neighbours['next']->id);
1127         // Normal user, orphan of groups, can only see non-grouped posts in separate groups.
1128         $this->setUser($user2);
1129         $_POST['group'] = 0;
1130         $this->assertEquals(0, groups_get_activity_group($cm2, true));
1132         $neighbours = forum_get_discussion_neighbours($cm2, $disc23);
1133         $this->assertEmpty($neighbours['prev']);
1134         $this->assertEmpty($neighbours['next']);
1136         $neighbours = forum_get_discussion_neighbours($cm2, $disc22);
1137         $this->assertEmpty($neighbours['prev']);
1138         $this->assertEquals($disc23->id, $neighbours['next']->id);
1140         $neighbours = forum_get_discussion_neighbours($cm2, $disc24);
1141         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1142         $this->assertEmpty($neighbours['next']);
1144         // Switching to viewing group 1.
1145         $this->setUser($user1);
1146         $_POST['group'] = $group1->id;
1147         $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1148         $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1150         // They can see non-grouped or same group.
1151         $neighbours = forum_get_discussion_neighbours($cm1, $disc11);
1152         $this->assertEmpty($neighbours['prev']);
1153         $this->assertEquals($disc13->id, $neighbours['next']->id);
1154         $neighbours = forum_get_discussion_neighbours($cm2, $disc21);
1155         $this->assertEmpty($neighbours['prev']);
1156         $this->assertEquals($disc23->id, $neighbours['next']->id);
1158         $neighbours = forum_get_discussion_neighbours($cm1, $disc13);
1159         $this->assertEquals($disc11->id, $neighbours['prev']->id);
1160         $this->assertEquals($disc15->id, $neighbours['next']->id);
1161         $neighbours = forum_get_discussion_neighbours($cm2, $disc23);
1162         $this->assertEquals($disc21->id, $neighbours['prev']->id);
1163         $this->assertEquals($disc25->id, $neighbours['next']->id);
1165         $neighbours = forum_get_discussion_neighbours($cm1, $disc15);
1166         $this->assertEquals($disc13->id, $neighbours['prev']->id);
1167         $this->assertEmpty($neighbours['next']);
1168         $neighbours = forum_get_discussion_neighbours($cm2, $disc25);
1169         $this->assertEquals($disc23->id, $neighbours['prev']->id);
1170         $this->assertEmpty($neighbours['next']);
1172         // Querying the neighbours of a discussion passing the wrong CM.
1173         $this->setExpectedException('coding_exception');
1174         forum_get_discussion_neighbours($cm2, $disc11);
1175     }
1177     public function test_count_discussion_replies_basic() {
1178         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1180         // Count the discussion replies in the forum.
1181         $result = forum_count_discussion_replies($forum->id);
1182         $this->assertCount(10, $result);
1183     }
1185     public function test_count_discussion_replies_limited() {
1186         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1187         // Adding limits shouldn't make a difference.
1188         $result = forum_count_discussion_replies($forum->id, "", 20);
1189         $this->assertCount(10, $result);
1190     }
1192     public function test_count_discussion_replies_paginated() {
1193         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1194         // Adding paging shouldn't make any difference.
1195         $result = forum_count_discussion_replies($forum->id, "", -1, 0, 100);
1196         $this->assertCount(10, $result);
1197     }
1199     public function test_count_discussion_replies_paginated_sorted() {
1200         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1201         // Specifying the forumsort should also give a good result. This follows a different path.
1202         $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 100);
1203         $this->assertCount(10, $result);
1204         foreach ($result as $row) {
1205             // Grab the first discussionid.
1206             $discussionid = array_shift($discussionids);
1207             $this->assertEquals($discussionid, $row->discussion);
1208         }
1209     }
1211     public function test_count_discussion_replies_limited_sorted() {
1212         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1213         // Adding limits, and a forumsort shouldn't make a difference.
1214         $result = forum_count_discussion_replies($forum->id, "d.id asc", 20);
1215         $this->assertCount(10, $result);
1216         foreach ($result as $row) {
1217             // Grab the first discussionid.
1218             $discussionid = array_shift($discussionids);
1219             $this->assertEquals($discussionid, $row->discussion);
1220         }
1221     }
1223     public function test_count_discussion_replies_paginated_sorted_small() {
1224         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1225         // Grabbing a smaller subset and they should be ordered as expected.
1226         $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 5);
1227         $this->assertCount(5, $result);
1228         foreach ($result as $row) {
1229             // Grab the first discussionid.
1230             $discussionid = array_shift($discussionids);
1231             $this->assertEquals($discussionid, $row->discussion);
1232         }
1233     }
1235     public function test_count_discussion_replies_paginated_sorted_small_reverse() {
1236         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1237         // Grabbing a smaller subset and they should be ordered as expected.
1238         $result = forum_count_discussion_replies($forum->id, "d.id desc", -1, 0, 5);
1239         $this->assertCount(5, $result);
1240         foreach ($result as $row) {
1241             // Grab the last discussionid.
1242             $discussionid = array_pop($discussionids);
1243             $this->assertEquals($discussionid, $row->discussion);
1244         }
1245     }
1247     public function test_count_discussion_replies_limited_sorted_small_reverse() {
1248         list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1249         // Adding limits, and a forumsort shouldn't make a difference.
1250         $result = forum_count_discussion_replies($forum->id, "d.id desc", 5);
1251         $this->assertCount(5, $result);
1252         foreach ($result as $row) {
1253             // Grab the last discussionid.
1254             $discussionid = array_pop($discussionids);
1255             $this->assertEquals($discussionid, $row->discussion);
1256         }
1257     }
1259     public function test_forum_view() {
1260         global $CFG;
1262         $CFG->enablecompletion = 1;
1263         $this->resetAfterTest();
1265         // Setup test data.
1266         $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
1267         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
1268                                                             array('completion' => 2, 'completionview' => 1));
1269         $context = context_module::instance($forum->cmid);
1270         $cm = get_coursemodule_from_instance('forum', $forum->id);
1272         // Trigger and capture the event.
1273         $sink = $this->redirectEvents();
1275         $this->setAdminUser();
1276         forum_view($forum, $course, $cm, $context);
1278         $events = $sink->get_events();
1279         // 2 additional events thanks to completion.
1280         $this->assertCount(3, $events);
1281         $event = array_pop($events);
1283         // Checking that the event contains the expected values.
1284         $this->assertInstanceOf('\mod_forum\event\course_module_viewed', $event);
1285         $this->assertEquals($context, $event->get_context());
1286         $url = new \moodle_url('/mod/forum/view.php', array('f' => $forum->id));
1287         $this->assertEquals($url, $event->get_url());
1288         $this->assertEventContextNotUsed($event);
1289         $this->assertNotEmpty($event->get_name());
1291         // Check completion status.
1292         $completion = new completion_info($course);
1293         $completiondata = $completion->get_data($cm);
1294         $this->assertEquals(1, $completiondata->completionstate);
1296     }
1298     /**
1299      * Test forum_discussion_view.
1300      */
1301     public function test_forum_discussion_view() {
1302         global $CFG, $USER;
1304         $this->resetAfterTest();
1306         // Setup test data.
1307         $course = $this->getDataGenerator()->create_course();
1308         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1309         $discussion = $this->create_single_discussion_with_replies($forum, $USER, 2);
1311         $context = context_module::instance($forum->cmid);
1312         $cm = get_coursemodule_from_instance('forum', $forum->id);
1314         // Trigger and capture the event.
1315         $sink = $this->redirectEvents();
1317         $this->setAdminUser();
1318         forum_discussion_view($context, $forum, $discussion);
1320         $events = $sink->get_events();
1321         $this->assertCount(1, $events);
1322         $event = array_pop($events);
1324         // Checking that the event contains the expected values.
1325         $this->assertInstanceOf('\mod_forum\event\discussion_viewed', $event);
1326         $this->assertEquals($context, $event->get_context());
1327         $expected = array($course->id, 'forum', 'view discussion', "discuss.php?d={$discussion->id}",
1328             $discussion->id, $forum->cmid);
1329         $this->assertEventLegacyLogData($expected, $event);
1330         $this->assertEventContextNotUsed($event);
1332         $this->assertNotEmpty($event->get_name());
1334     }
1336     /**
1337      * Create a new course, forum, and user with a number of discussions and replies.
1338      *
1339      * @param int $discussioncount The number of discussions to create
1340      * @param int $replycount The number of replies to create in each discussion
1341      * @return array Containing the created forum object, and the ids of the created discussions.
1342      */
1343     protected function create_multiple_discussions_with_replies($discussioncount, $replycount) {
1344         $this->resetAfterTest();
1346         // Setup the content.
1347         $user = $this->getDataGenerator()->create_user();
1348         $course = $this->getDataGenerator()->create_course();
1349         $record = new stdClass();
1350         $record->course = $course->id;
1351         $forum = $this->getDataGenerator()->create_module('forum', $record);
1353         // Create 10 discussions with replies.
1354         $discussionids = array();
1355         for ($i = 0; $i < $discussioncount; $i++) {
1356             $discussion = $this->create_single_discussion_with_replies($forum, $user, $replycount);
1357             $discussionids[] = $discussion->id;
1358         }
1359         return array($forum, $discussionids);
1360     }
1362     /**
1363      * Create a discussion with a number of replies.
1364      *
1365      * @param object $forum The forum which has been created
1366      * @param object $user The user making the discussion and replies
1367      * @param int $replycount The number of replies
1368      * @return object $discussion
1369      */
1370     protected function create_single_discussion_with_replies($forum, $user, $replycount) {
1371         global $DB;
1373         $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1375         $record = new stdClass();
1376         $record->course = $forum->course;
1377         $record->forum = $forum->id;
1378         $record->userid = $user->id;
1379         $discussion = $generator->create_discussion($record);
1381         // Retrieve the first post.
1382         $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1384         // Create the replies.
1385         $post = new stdClass();
1386         $post->userid = $user->id;
1387         $post->discussion = $discussion->id;
1388         $post->parent = $replyto->id;
1390         for ($i = 0; $i < $replycount; $i++) {
1391             $generator->create_post($post);
1392         }
1394         return $discussion;
1395     }