[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/forum/tests/ -> lib_test.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  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   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  require_once($CFG->dirroot . '/mod/forum/lib.php');
  29  require_once($CFG->dirroot . '/rating/lib.php');
  30  
  31  class mod_forum_lib_testcase extends advanced_testcase {
  32  
  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      }
  38  
  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      }
  44  
  45      public function test_forum_trigger_content_uploaded_event() {
  46          $this->resetAfterTest();
  47  
  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);
  52  
  53          $this->setUser($user->id);
  54          $fakepost = (object) array('id' => 123, 'message' => 'Yay!', 'discussion' => 100);
  55          $cm = get_coursemodule_from_instance('forum', $forum->id);
  56  
  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);
  67  
  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();
  72  
  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      }
  94  
  95      public function test_forum_get_courses_user_posted_in() {
  96          $this->resetAfterTest();
  97  
  98          $user1 = $this->getDataGenerator()->create_user();
  99          $user2 = $this->getDataGenerator()->create_user();
 100          $user3 = $this->getDataGenerator()->create_user();
 101  
 102          $course1 = $this->getDataGenerator()->create_course();
 103          $course2 = $this->getDataGenerator()->create_course();
 104          $course3 = $this->getDataGenerator()->create_course();
 105  
 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);
 110  
 111          $record = new stdClass();
 112          $record->course = $course2->id;
 113          $forum2 = $this->getDataGenerator()->create_module('forum', $record);
 114  
 115          $record = new stdClass();
 116          $record->course = $course3->id;
 117          $forum3 = $this->getDataGenerator()->create_module('forum', $record);
 118  
 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);
 123  
 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);
 130  
 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);
 136  
 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);
 143  
 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);
 150  
 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);
 158  
 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);
 162  
 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);
 169  
 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));
 177  
 178          }
 179  
 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      }
 188  
 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;
 194  
 195          $this->resetAfterTest();
 196  
 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);
 202  
 203          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
 204          $forumforce = $this->getDataGenerator()->create_module('forum', $options);
 205  
 206          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
 207          $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
 208  
 209          // Allow force.
 210          $CFG->forum_allowforcedreadtracking = 1;
 211  
 212          // User on, forum off, should be off.
 213          $result = forum_tp_can_track_forums($forumoff, $useron);
 214          $this->assertEquals(false, $result);
 215  
 216          // User on, forum on, should be on.
 217          $result = forum_tp_can_track_forums($forumforce, $useron);
 218          $this->assertEquals(true, $result);
 219  
 220          // User on, forum optional, should be on.
 221          $result = forum_tp_can_track_forums($forumoptional, $useron);
 222          $this->assertEquals(true, $result);
 223  
 224          // User off, forum off, should be off.
 225          $result = forum_tp_can_track_forums($forumoff, $useroff);
 226          $this->assertEquals(false, $result);
 227  
 228          // User off, forum force, should be on.
 229          $result = forum_tp_can_track_forums($forumforce, $useroff);
 230          $this->assertEquals(true, $result);
 231  
 232          // User off, forum optional, should be off.
 233          $result = forum_tp_can_track_forums($forumoptional, $useroff);
 234          $this->assertEquals(false, $result);
 235  
 236          // Don't allow force.
 237          $CFG->forum_allowforcedreadtracking = 0;
 238  
 239          // User on, forum off, should be off.
 240          $result = forum_tp_can_track_forums($forumoff, $useron);
 241          $this->assertEquals(false, $result);
 242  
 243          // User on, forum on, should be on.
 244          $result = forum_tp_can_track_forums($forumforce, $useron);
 245          $this->assertEquals(true, $result);
 246  
 247          // User on, forum optional, should be on.
 248          $result = forum_tp_can_track_forums($forumoptional, $useron);
 249          $this->assertEquals(true, $result);
 250  
 251          // User off, forum off, should be off.
 252          $result = forum_tp_can_track_forums($forumoff, $useroff);
 253          $this->assertEquals(false, $result);
 254  
 255          // User off, forum force, should be off.
 256          $result = forum_tp_can_track_forums($forumforce, $useroff);
 257          $this->assertEquals(false, $result);
 258  
 259          // User off, forum optional, should be off.
 260          $result = forum_tp_can_track_forums($forumoptional, $useroff);
 261          $this->assertEquals(false, $result);
 262  
 263      }
 264  
 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;
 270  
 271          $this->resetAfterTest();
 272  
 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);
 278  
 279          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
 280          $forumforce = $this->getDataGenerator()->create_module('forum', $options);
 281  
 282          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
 283          $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
 284  
 285          // Allow force.
 286          $CFG->forum_allowforcedreadtracking = 1;
 287  
 288          // User on, forum off, should be off.
 289          $result = forum_tp_is_tracked($forumoff, $useron);
 290          $this->assertEquals(false, $result);
 291  
 292          // User on, forum force, should be on.
 293          $result = forum_tp_is_tracked($forumforce, $useron);
 294          $this->assertEquals(true, $result);
 295  
 296          // User on, forum optional, should be on.
 297          $result = forum_tp_is_tracked($forumoptional, $useron);
 298          $this->assertEquals(true, $result);
 299  
 300          // User off, forum off, should be off.
 301          $result = forum_tp_is_tracked($forumoff, $useroff);
 302          $this->assertEquals(false, $result);
 303  
 304          // User off, forum force, should be on.
 305          $result = forum_tp_is_tracked($forumforce, $useroff);
 306          $this->assertEquals(true, $result);
 307  
 308          // User off, forum optional, should be off.
 309          $result = forum_tp_is_tracked($forumoptional, $useroff);
 310          $this->assertEquals(false, $result);
 311  
 312          // Don't allow force.
 313          $CFG->forum_allowforcedreadtracking = 0;
 314  
 315          // User on, forum off, should be off.
 316          $result = forum_tp_is_tracked($forumoff, $useron);
 317          $this->assertEquals(false, $result);
 318  
 319          // User on, forum force, should be on.
 320          $result = forum_tp_is_tracked($forumforce, $useron);
 321          $this->assertEquals(true, $result);
 322  
 323          // User on, forum optional, should be on.
 324          $result = forum_tp_is_tracked($forumoptional, $useron);
 325          $this->assertEquals(true, $result);
 326  
 327          // User off, forum off, should be off.
 328          $result = forum_tp_is_tracked($forumoff, $useroff);
 329          $this->assertEquals(false, $result);
 330  
 331          // User off, forum force, should be off.
 332          $result = forum_tp_is_tracked($forumforce, $useroff);
 333          $this->assertEquals(false, $result);
 334  
 335          // User off, forum optional, should be off.
 336          $result = forum_tp_is_tracked($forumoptional, $useroff);
 337          $this->assertEquals(false, $result);
 338  
 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);
 344  
 345          // Allow force.
 346          $CFG->forum_allowforcedreadtracking = 1;
 347  
 348          // User on, preference off, forum force, should be on.
 349          $result = forum_tp_is_tracked($forumforce, $useron);
 350          $this->assertEquals(true, $result);
 351  
 352          // User on, preference off, forum optional, should be on.
 353          $result = forum_tp_is_tracked($forumoptional, $useron);
 354          $this->assertEquals(false, $result);
 355  
 356          // User off, preference off, forum force, should be on.
 357          $result = forum_tp_is_tracked($forumforce, $useroff);
 358          $this->assertEquals(true, $result);
 359  
 360          // User off, preference off, forum optional, should be off.
 361          $result = forum_tp_is_tracked($forumoptional, $useroff);
 362          $this->assertEquals(false, $result);
 363  
 364          // Don't allow force.
 365          $CFG->forum_allowforcedreadtracking = 0;
 366  
 367          // User on, preference off, forum force, should be on.
 368          $result = forum_tp_is_tracked($forumforce, $useron);
 369          $this->assertEquals(false, $result);
 370  
 371          // User on, preference off, forum optional, should be on.
 372          $result = forum_tp_is_tracked($forumoptional, $useron);
 373          $this->assertEquals(false, $result);
 374  
 375          // User off, preference off, forum force, should be off.
 376          $result = forum_tp_is_tracked($forumforce, $useroff);
 377          $this->assertEquals(false, $result);
 378  
 379          // User off, preference off, forum optional, should be off.
 380          $result = forum_tp_is_tracked($forumoptional, $useroff);
 381          $this->assertEquals(false, $result);
 382      }
 383  
 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;
 389  
 390          $this->resetAfterTest();
 391  
 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);
 397  
 398          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
 399          $forumforce = $this->getDataGenerator()->create_module('forum', $options);
 400  
 401          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
 402          $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
 403  
 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);
 410  
 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);
 417  
 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);
 425  
 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);
 432  
 433          // Allow force.
 434          $CFG->forum_allowforcedreadtracking = 1;
 435  
 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);
 443  
 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]));
 450  
 451          // Don't allow force.
 452          $CFG->forum_allowforcedreadtracking = 0;
 453  
 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);
 461  
 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]));
 467  
 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);
 473  
 474          // Allow force.
 475          $CFG->forum_allowforcedreadtracking = 1;
 476  
 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]));
 483  
 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]));
 490  
 491          // Don't allow force.
 492          $CFG->forum_allowforcedreadtracking = 0;
 493  
 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]));
 499  
 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      }
 506  
 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;
 512  
 513          $this->resetAfterTest();
 514  
 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);
 520  
 521          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_FORCED); // On.
 522          $forumforce = $this->getDataGenerator()->create_module('forum', $options);
 523  
 524          $options = array('course' => $course->id, 'trackingtype' => FORUM_TRACKING_OPTIONAL); // Optional.
 525          $forumoptional = $this->getDataGenerator()->create_module('forum', $options);
 526  
 527          // Allow force.
 528          $CFG->forum_allowforcedreadtracking = 1;
 529  
 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]));
 534  
 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]));
 540  
 541          // Don't allow force.
 542          $CFG->forum_allowforcedreadtracking = 0;
 543  
 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]));
 548  
 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]));
 555  
 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);
 561  
 562          // Allow force.
 563          $CFG->forum_allowforcedreadtracking = 1;
 564  
 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]));
 570  
 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]));
 576  
 577          // Don't allow force.
 578          $CFG->forum_allowforcedreadtracking = 0;
 579  
 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]));
 586  
 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      }
 594  
 595      /**
 596       * Test subscription using automatic subscription on create.
 597       */
 598      public function test_forum_auto_subscribe_on_create() {
 599          global $CFG;
 600  
 601          $this->resetAfterTest();
 602  
 603          $usercount = 5;
 604          $course = $this->getDataGenerator()->create_course();
 605          $users = array();
 606  
 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          }
 612  
 613          $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); // Automatic Subscription.
 614          $forum = $this->getDataGenerator()->create_module('forum', $options);
 615  
 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      }
 622  
 623      /**
 624       * Test subscription using forced subscription on create.
 625       */
 626      public function test_forum_forced_subscribe_on_create() {
 627          global $CFG;
 628  
 629          $this->resetAfterTest();
 630  
 631          $usercount = 5;
 632          $course = $this->getDataGenerator()->create_course();
 633          $users = array();
 634  
 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          }
 640  
 641          $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); // Forced subscription.
 642          $forum = $this->getDataGenerator()->create_module('forum', $options);
 643  
 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      }
 650  
 651      /**
 652       * Test subscription using optional subscription on create.
 653       */
 654      public function test_forum_optional_subscribe_on_create() {
 655          global $CFG;
 656  
 657          $this->resetAfterTest();
 658  
 659          $usercount = 5;
 660          $course = $this->getDataGenerator()->create_course();
 661          $users = array();
 662  
 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          }
 668  
 669          $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); // Subscription optional.
 670          $forum = $this->getDataGenerator()->create_module('forum', $options);
 671  
 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      }
 679  
 680      /**
 681       * Test subscription using disallow subscription on create.
 682       */
 683      public function test_forum_disallow_subscribe_on_create() {
 684          global $CFG;
 685  
 686          $this->resetAfterTest();
 687  
 688          $usercount = 5;
 689          $course = $this->getDataGenerator()->create_course();
 690          $users = array();
 691  
 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          }
 697  
 698          $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); // Subscription prevented.
 699          $forum = $this->getDataGenerator()->create_module('forum', $options);
 700  
 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      }
 708  
 709      /**
 710       * Test that context fetching returns the appropriate context.
 711       */
 712      public function test_forum_get_context() {
 713          global $DB, $PAGE;
 714  
 715          $this->resetAfterTest();
 716  
 717          // Setup test data.
 718          $course = $this->getDataGenerator()->create_course();
 719          $coursecontext = \context_course::instance($course->id);
 720  
 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);
 725  
 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);
 734  
 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);
 742  
 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);
 750  
 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);
 755  
 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);
 763  
 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);
 771  
 772          // Now specify the page context of the course instead..
 773          $PAGE = new moodle_page();
 774          $PAGE->set_context($coursecontext);
 775  
 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);
 783  
 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      }
 792  
 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();
 799  
 800          $timenow = time();
 801          $timenext = $timenow;
 802  
 803          // Setup test data.
 804          $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
 805          $course = $this->getDataGenerator()->create_course();
 806          $user = $this->getDataGenerator()->create_user();
 807          $user2 = $this->getDataGenerator()->create_user();
 808  
 809          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
 810          $cm = get_coursemodule_from_instance('forum', $forum->id);
 811          $context = context_module::instance($cm->id);
 812  
 813          $record = new stdClass();
 814          $record->course = $course->id;
 815          $record->userid = $user->id;
 816          $record->forum = $forum->id;
 817          $record->timemodified = time();
 818          $disc1 = $forumgen->create_discussion($record);
 819          $record->timemodified++;
 820          $disc2 = $forumgen->create_discussion($record);
 821          $record->timemodified++;
 822          $disc3 = $forumgen->create_discussion($record);
 823          $record->timemodified++;
 824          $disc4 = $forumgen->create_discussion($record);
 825          $record->timemodified++;
 826          $disc5 = $forumgen->create_discussion($record);
 827  
 828          // Getting the neighbours.
 829          $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
 830          $this->assertEmpty($neighbours['prev']);
 831          $this->assertEquals($disc2->id, $neighbours['next']->id);
 832  
 833          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
 834          $this->assertEquals($disc1->id, $neighbours['prev']->id);
 835          $this->assertEquals($disc3->id, $neighbours['next']->id);
 836  
 837          $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
 838          $this->assertEquals($disc2->id, $neighbours['prev']->id);
 839          $this->assertEquals($disc4->id, $neighbours['next']->id);
 840  
 841          $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum);
 842          $this->assertEquals($disc3->id, $neighbours['prev']->id);
 843          $this->assertEquals($disc5->id, $neighbours['next']->id);
 844  
 845          $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
 846          $this->assertEquals($disc4->id, $neighbours['prev']->id);
 847          $this->assertEmpty($neighbours['next']);
 848  
 849          // Post in some discussions. We manually update the discussion record because
 850          // the data generator plays with timemodified in a way that would break this test.
 851          $record->timemodified++;
 852          $disc1->timemodified = $record->timemodified;
 853          $DB->update_record('forum_discussions', $disc1);
 854  
 855          $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
 856          $this->assertEquals($disc4->id, $neighbours['prev']->id);
 857          $this->assertEquals($disc1->id, $neighbours['next']->id);
 858  
 859          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
 860          $this->assertEmpty($neighbours['prev']);
 861          $this->assertEquals($disc3->id, $neighbours['next']->id);
 862  
 863          $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
 864          $this->assertEquals($disc5->id, $neighbours['prev']->id);
 865          $this->assertEmpty($neighbours['next']);
 866  
 867          // After some discussions were created.
 868          $record->timemodified++;
 869          $disc6 = $forumgen->create_discussion($record);
 870          $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum);
 871          $this->assertEquals($disc1->id, $neighbours['prev']->id);
 872          $this->assertEmpty($neighbours['next']);
 873  
 874          $record->timemodified++;
 875          $disc7 = $forumgen->create_discussion($record);
 876          $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum);
 877          $this->assertEquals($disc6->id, $neighbours['prev']->id);
 878          $this->assertEmpty($neighbours['next']);
 879  
 880          // Adding timed discussions.
 881          $CFG->forum_enabletimedposts = true;
 882          $now = $record->timemodified;
 883          $past = $now - 60;
 884          $future = $now + 60;
 885  
 886          $record = new stdClass();
 887          $record->course = $course->id;
 888          $record->userid = $user->id;
 889          $record->forum = $forum->id;
 890          $record->timestart = $past;
 891          $record->timeend = $future;
 892          $record->timemodified = $now;
 893          $record->timemodified++;
 894          $disc8 = $forumgen->create_discussion($record);
 895          $record->timemodified++;
 896          $record->timestart = $future;
 897          $record->timeend = 0;
 898          $disc9 = $forumgen->create_discussion($record);
 899          $record->timemodified++;
 900          $record->timestart = 0;
 901          $record->timeend = 0;
 902          $disc10 = $forumgen->create_discussion($record);
 903          $record->timemodified++;
 904          $record->timestart = 0;
 905          $record->timeend = $past;
 906          $disc11 = $forumgen->create_discussion($record);
 907          $record->timemodified++;
 908          $record->timestart = $past;
 909          $record->timeend = $future;
 910          $disc12 = $forumgen->create_discussion($record);
 911          $record->timemodified++;
 912          $record->timestart = $future + 1; // Should be last post for those that can see it.
 913          $record->timeend = 0;
 914          $disc13 = $forumgen->create_discussion($record);
 915  
 916          // Admin user ignores the timed settings of discussions.
 917          // Post ordering taking into account timestart:
 918          //  8 = t
 919          // 10 = t+3
 920          // 11 = t+4
 921          // 12 = t+5
 922          //  9 = t+60
 923          // 13 = t+61.
 924          $this->setAdminUser();
 925          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
 926          $this->assertEquals($disc7->id, $neighbours['prev']->id);
 927          $this->assertEquals($disc10->id, $neighbours['next']->id);
 928  
 929          $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
 930          $this->assertEquals($disc12->id, $neighbours['prev']->id);
 931          $this->assertEquals($disc13->id, $neighbours['next']->id);
 932  
 933          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
 934          $this->assertEquals($disc8->id, $neighbours['prev']->id);
 935          $this->assertEquals($disc11->id, $neighbours['next']->id);
 936  
 937          $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
 938          $this->assertEquals($disc10->id, $neighbours['prev']->id);
 939          $this->assertEquals($disc12->id, $neighbours['next']->id);
 940  
 941          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
 942          $this->assertEquals($disc11->id, $neighbours['prev']->id);
 943          $this->assertEquals($disc9->id, $neighbours['next']->id);
 944  
 945          $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum);
 946          $this->assertEquals($disc9->id, $neighbours['prev']->id);
 947          $this->assertEmpty($neighbours['next']);
 948  
 949          // Normal user can see their own timed discussions.
 950          $this->setUser($user);
 951          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
 952          $this->assertEquals($disc7->id, $neighbours['prev']->id);
 953          $this->assertEquals($disc10->id, $neighbours['next']->id);
 954  
 955          $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
 956          $this->assertEquals($disc12->id, $neighbours['prev']->id);
 957          $this->assertEquals($disc13->id, $neighbours['next']->id);
 958  
 959          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
 960          $this->assertEquals($disc8->id, $neighbours['prev']->id);
 961          $this->assertEquals($disc11->id, $neighbours['next']->id);
 962  
 963          $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
 964          $this->assertEquals($disc10->id, $neighbours['prev']->id);
 965          $this->assertEquals($disc12->id, $neighbours['next']->id);
 966  
 967          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
 968          $this->assertEquals($disc11->id, $neighbours['prev']->id);
 969          $this->assertEquals($disc9->id, $neighbours['next']->id);
 970  
 971          $neighbours = forum_get_discussion_neighbours($cm, $disc13, $forum);
 972          $this->assertEquals($disc9->id, $neighbours['prev']->id);
 973          $this->assertEmpty($neighbours['next']);
 974  
 975          // Normal user does not ignore timed settings.
 976          $this->setUser($user2);
 977          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
 978          $this->assertEquals($disc7->id, $neighbours['prev']->id);
 979          $this->assertEquals($disc10->id, $neighbours['next']->id);
 980  
 981          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
 982          $this->assertEquals($disc8->id, $neighbours['prev']->id);
 983          $this->assertEquals($disc12->id, $neighbours['next']->id);
 984  
 985          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
 986          $this->assertEquals($disc10->id, $neighbours['prev']->id);
 987          $this->assertEmpty($neighbours['next']);
 988  
 989          // Reset to normal mode.
 990          $CFG->forum_enabletimedposts = false;
 991          $this->setAdminUser();
 992  
 993          // Two discussions with identical timemodified will sort by id.
 994          $record->timemodified += 25;
 995          $DB->update_record('forum_discussions', (object) array('id' => $disc3->id, 'timemodified' => $record->timemodified));
 996          $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $record->timemodified));
 997          $DB->update_record('forum_discussions', (object) array('id' => $disc12->id, 'timemodified' => $record->timemodified - 5));
 998          $disc2 = $DB->get_record('forum_discussions', array('id' => $disc2->id));
 999          $disc3 = $DB->get_record('forum_discussions', array('id' => $disc3->id));
1000  
1001          $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1002          $this->assertEquals($disc2->id, $neighbours['prev']->id);
1003          $this->assertEmpty($neighbours['next']);
1004  
1005          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1006          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1007          $this->assertEquals($disc3->id, $neighbours['next']->id);
1008  
1009          // Set timemodified to not be identical.
1010          $DB->update_record('forum_discussions', (object) array('id' => $disc2->id, 'timemodified' => $record->timemodified - 1));
1011  
1012          // Test pinned posts behave correctly.
1013          $disc8->pinned = FORUM_DISCUSSION_PINNED;
1014          $DB->update_record('forum_discussions', (object) array('id' => $disc8->id, 'pinned' => $disc8->pinned));
1015          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1016          $this->assertEquals($disc3->id, $neighbours['prev']->id);
1017          $this->assertEmpty($neighbours['next']);
1018  
1019          $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1020          $this->assertEquals($disc2->id, $neighbours['prev']->id);
1021          $this->assertEquals($disc8->id, $neighbours['next']->id);
1022  
1023          // Test 3 pinned posts.
1024          $disc6->pinned = FORUM_DISCUSSION_PINNED;
1025          $DB->update_record('forum_discussions', (object) array('id' => $disc6->id, 'pinned' => $disc6->pinned));
1026          $disc4->pinned = FORUM_DISCUSSION_PINNED;
1027          $DB->update_record('forum_discussions', (object) array('id' => $disc4->id, 'pinned' => $disc4->pinned));
1028  
1029          $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum);
1030          $this->assertEquals($disc4->id, $neighbours['prev']->id);
1031          $this->assertEquals($disc8->id, $neighbours['next']->id);
1032  
1033          $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum);
1034          $this->assertEquals($disc3->id, $neighbours['prev']->id);
1035          $this->assertEquals($disc6->id, $neighbours['next']->id);
1036  
1037          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1038          $this->assertEquals($disc6->id, $neighbours['prev']->id);
1039          $this->assertEmpty($neighbours['next']);
1040      }
1041  
1042      /**
1043       * Test getting the neighbour threads of a blog-like forum.
1044       */
1045      public function test_forum_get_neighbours_blog() {
1046          global $CFG, $DB;
1047          $this->resetAfterTest();
1048  
1049          $timenow = time();
1050          $timenext = $timenow;
1051  
1052          // Setup test data.
1053          $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1054          $course = $this->getDataGenerator()->create_course();
1055          $user = $this->getDataGenerator()->create_user();
1056          $user2 = $this->getDataGenerator()->create_user();
1057  
1058          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog'));
1059          $cm = get_coursemodule_from_instance('forum', $forum->id);
1060          $context = context_module::instance($cm->id);
1061  
1062          $record = new stdClass();
1063          $record->course = $course->id;
1064          $record->userid = $user->id;
1065          $record->forum = $forum->id;
1066          $record->timemodified = time();
1067          $disc1 = $forumgen->create_discussion($record);
1068          $record->timemodified++;
1069          $disc2 = $forumgen->create_discussion($record);
1070          $record->timemodified++;
1071          $disc3 = $forumgen->create_discussion($record);
1072          $record->timemodified++;
1073          $disc4 = $forumgen->create_discussion($record);
1074          $record->timemodified++;
1075          $disc5 = $forumgen->create_discussion($record);
1076  
1077          // Getting the neighbours.
1078          $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
1079          $this->assertEmpty($neighbours['prev']);
1080          $this->assertEquals($disc2->id, $neighbours['next']->id);
1081  
1082          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1083          $this->assertEquals($disc1->id, $neighbours['prev']->id);
1084          $this->assertEquals($disc3->id, $neighbours['next']->id);
1085  
1086          $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1087          $this->assertEquals($disc2->id, $neighbours['prev']->id);
1088          $this->assertEquals($disc4->id, $neighbours['next']->id);
1089  
1090          $neighbours = forum_get_discussion_neighbours($cm, $disc4, $forum);
1091          $this->assertEquals($disc3->id, $neighbours['prev']->id);
1092          $this->assertEquals($disc5->id, $neighbours['next']->id);
1093  
1094          $neighbours = forum_get_discussion_neighbours($cm, $disc5, $forum);
1095          $this->assertEquals($disc4->id, $neighbours['prev']->id);
1096          $this->assertEmpty($neighbours['next']);
1097  
1098          // Make sure that the thread's timemodified does not affect the order.
1099          $record->timemodified++;
1100          $disc1->timemodified = $record->timemodified;
1101          $DB->update_record('forum_discussions', $disc1);
1102  
1103          $neighbours = forum_get_discussion_neighbours($cm, $disc1, $forum);
1104          $this->assertEmpty($neighbours['prev']);
1105          $this->assertEquals($disc2->id, $neighbours['next']->id);
1106  
1107          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1108          $this->assertEquals($disc1->id, $neighbours['prev']->id);
1109          $this->assertEquals($disc3->id, $neighbours['next']->id);
1110  
1111          // Add another blog post.
1112          $record->timemodified++;
1113          $disc6 = $forumgen->create_discussion($record);
1114          $neighbours = forum_get_discussion_neighbours($cm, $disc6, $forum);
1115          $this->assertEquals($disc5->id, $neighbours['prev']->id);
1116          $this->assertEmpty($neighbours['next']);
1117  
1118          $record->timemodified++;
1119          $disc7 = $forumgen->create_discussion($record);
1120          $neighbours = forum_get_discussion_neighbours($cm, $disc7, $forum);
1121          $this->assertEquals($disc6->id, $neighbours['prev']->id);
1122          $this->assertEmpty($neighbours['next']);
1123  
1124          // Adding timed discussions.
1125          $CFG->forum_enabletimedposts = true;
1126          $now = $record->timemodified;
1127          $past = $now - 60;
1128          $future = $now + 60;
1129  
1130          $record = new stdClass();
1131          $record->course = $course->id;
1132          $record->userid = $user->id;
1133          $record->forum = $forum->id;
1134          $record->timestart = $past;
1135          $record->timeend = $future;
1136          $record->timemodified = $now;
1137          $record->timemodified++;
1138          $disc8 = $forumgen->create_discussion($record);
1139          $record->timemodified++;
1140          $record->timestart = $future;
1141          $record->timeend = 0;
1142          $disc9 = $forumgen->create_discussion($record);
1143          $record->timemodified++;
1144          $record->timestart = 0;
1145          $record->timeend = 0;
1146          $disc10 = $forumgen->create_discussion($record);
1147          $record->timemodified++;
1148          $record->timestart = 0;
1149          $record->timeend = $past;
1150          $disc11 = $forumgen->create_discussion($record);
1151          $record->timemodified++;
1152          $record->timestart = $past;
1153          $record->timeend = $future;
1154          $disc12 = $forumgen->create_discussion($record);
1155  
1156          // Admin user ignores the timed settings of discussions.
1157          $this->setAdminUser();
1158          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1159          $this->assertEquals($disc7->id, $neighbours['prev']->id);
1160          $this->assertEquals($disc9->id, $neighbours['next']->id);
1161  
1162          $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
1163          $this->assertEquals($disc8->id, $neighbours['prev']->id);
1164          $this->assertEquals($disc10->id, $neighbours['next']->id);
1165  
1166          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1167          $this->assertEquals($disc9->id, $neighbours['prev']->id);
1168          $this->assertEquals($disc11->id, $neighbours['next']->id);
1169  
1170          $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
1171          $this->assertEquals($disc10->id, $neighbours['prev']->id);
1172          $this->assertEquals($disc12->id, $neighbours['next']->id);
1173  
1174          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1175          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1176          $this->assertEmpty($neighbours['next']);
1177  
1178          // Normal user can see their own timed discussions.
1179          $this->setUser($user);
1180          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1181          $this->assertEquals($disc7->id, $neighbours['prev']->id);
1182          $this->assertEquals($disc9->id, $neighbours['next']->id);
1183  
1184          $neighbours = forum_get_discussion_neighbours($cm, $disc9, $forum);
1185          $this->assertEquals($disc8->id, $neighbours['prev']->id);
1186          $this->assertEquals($disc10->id, $neighbours['next']->id);
1187  
1188          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1189          $this->assertEquals($disc9->id, $neighbours['prev']->id);
1190          $this->assertEquals($disc11->id, $neighbours['next']->id);
1191  
1192          $neighbours = forum_get_discussion_neighbours($cm, $disc11, $forum);
1193          $this->assertEquals($disc10->id, $neighbours['prev']->id);
1194          $this->assertEquals($disc12->id, $neighbours['next']->id);
1195  
1196          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1197          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1198          $this->assertEmpty($neighbours['next']);
1199  
1200          // Normal user does not ignore timed settings.
1201          $this->setUser($user2);
1202          $neighbours = forum_get_discussion_neighbours($cm, $disc8, $forum);
1203          $this->assertEquals($disc7->id, $neighbours['prev']->id);
1204          $this->assertEquals($disc10->id, $neighbours['next']->id);
1205  
1206          $neighbours = forum_get_discussion_neighbours($cm, $disc10, $forum);
1207          $this->assertEquals($disc8->id, $neighbours['prev']->id);
1208          $this->assertEquals($disc12->id, $neighbours['next']->id);
1209  
1210          $neighbours = forum_get_discussion_neighbours($cm, $disc12, $forum);
1211          $this->assertEquals($disc10->id, $neighbours['prev']->id);
1212          $this->assertEmpty($neighbours['next']);
1213  
1214          // Reset to normal mode.
1215          $CFG->forum_enabletimedposts = false;
1216          $this->setAdminUser();
1217  
1218          $record->timemodified++;
1219          // Two blog posts with identical creation time will sort by id.
1220          $DB->update_record('forum_posts', (object) array('id' => $disc2->firstpost, 'created' => $record->timemodified));
1221          $DB->update_record('forum_posts', (object) array('id' => $disc3->firstpost, 'created' => $record->timemodified));
1222  
1223          $neighbours = forum_get_discussion_neighbours($cm, $disc2, $forum);
1224          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1225          $this->assertEquals($disc3->id, $neighbours['next']->id);
1226  
1227          $neighbours = forum_get_discussion_neighbours($cm, $disc3, $forum);
1228          $this->assertEquals($disc2->id, $neighbours['prev']->id);
1229          $this->assertEmpty($neighbours['next']);
1230      }
1231  
1232      /**
1233       * Test getting the neighbour threads of a discussion.
1234       */
1235      public function test_forum_get_neighbours_with_groups() {
1236          $this->resetAfterTest();
1237  
1238          $timenow = time();
1239          $timenext = $timenow;
1240  
1241          // Setup test data.
1242          $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1243          $course = $this->getDataGenerator()->create_course();
1244          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1245          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1246          $user1 = $this->getDataGenerator()->create_user();
1247          $user2 = $this->getDataGenerator()->create_user();
1248          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
1249          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
1250          $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id));
1251  
1252          $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => VISIBLEGROUPS));
1253          $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'groupmode' => SEPARATEGROUPS));
1254          $cm1 = get_coursemodule_from_instance('forum', $forum1->id);
1255          $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
1256          $context1 = context_module::instance($cm1->id);
1257          $context2 = context_module::instance($cm2->id);
1258  
1259          // Creating discussions in both forums.
1260          $record = new stdClass();
1261          $record->course = $course->id;
1262          $record->userid = $user1->id;
1263          $record->forum = $forum1->id;
1264          $record->groupid = $group1->id;
1265          $record->timemodified = time();
1266          $disc11 = $forumgen->create_discussion($record);
1267          $record->forum = $forum2->id;
1268          $record->timemodified++;
1269          $disc21 = $forumgen->create_discussion($record);
1270  
1271          $record->timemodified++;
1272          $record->userid = $user2->id;
1273          $record->forum = $forum1->id;
1274          $record->groupid = $group2->id;
1275          $disc12 = $forumgen->create_discussion($record);
1276          $record->forum = $forum2->id;
1277          $disc22 = $forumgen->create_discussion($record);
1278  
1279          $record->timemodified++;
1280          $record->userid = $user1->id;
1281          $record->forum = $forum1->id;
1282          $record->groupid = null;
1283          $disc13 = $forumgen->create_discussion($record);
1284          $record->forum = $forum2->id;
1285          $disc23 = $forumgen->create_discussion($record);
1286  
1287          $record->timemodified++;
1288          $record->userid = $user2->id;
1289          $record->forum = $forum1->id;
1290          $record->groupid = $group2->id;
1291          $disc14 = $forumgen->create_discussion($record);
1292          $record->forum = $forum2->id;
1293          $disc24 = $forumgen->create_discussion($record);
1294  
1295          $record->timemodified++;
1296          $record->userid = $user1->id;
1297          $record->forum = $forum1->id;
1298          $record->groupid = $group1->id;
1299          $disc15 = $forumgen->create_discussion($record);
1300          $record->forum = $forum2->id;
1301          $disc25 = $forumgen->create_discussion($record);
1302  
1303          // Admin user can see all groups.
1304          $this->setAdminUser();
1305          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1306          $this->assertEmpty($neighbours['prev']);
1307          $this->assertEquals($disc12->id, $neighbours['next']->id);
1308          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1309          $this->assertEmpty($neighbours['prev']);
1310          $this->assertEquals($disc22->id, $neighbours['next']->id);
1311  
1312          $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1313          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1314          $this->assertEquals($disc13->id, $neighbours['next']->id);
1315          $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1316          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1317          $this->assertEquals($disc23->id, $neighbours['next']->id);
1318  
1319          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1320          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1321          $this->assertEquals($disc14->id, $neighbours['next']->id);
1322          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1323          $this->assertEquals($disc22->id, $neighbours['prev']->id);
1324          $this->assertEquals($disc24->id, $neighbours['next']->id);
1325  
1326          $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1);
1327          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1328          $this->assertEquals($disc15->id, $neighbours['next']->id);
1329          $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1330          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1331          $this->assertEquals($disc25->id, $neighbours['next']->id);
1332  
1333          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1334          $this->assertEquals($disc14->id, $neighbours['prev']->id);
1335          $this->assertEmpty($neighbours['next']);
1336          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1337          $this->assertEquals($disc24->id, $neighbours['prev']->id);
1338          $this->assertEmpty($neighbours['next']);
1339  
1340          // Admin user is only viewing group 1.
1341          $_POST['group'] = $group1->id;
1342          $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1343          $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1344  
1345          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1346          $this->assertEmpty($neighbours['prev']);
1347          $this->assertEquals($disc13->id, $neighbours['next']->id);
1348          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1349          $this->assertEmpty($neighbours['prev']);
1350          $this->assertEquals($disc23->id, $neighbours['next']->id);
1351  
1352          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1353          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1354          $this->assertEquals($disc15->id, $neighbours['next']->id);
1355          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1356          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1357          $this->assertEquals($disc25->id, $neighbours['next']->id);
1358  
1359          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1360          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1361          $this->assertEmpty($neighbours['next']);
1362          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1363          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1364          $this->assertEmpty($neighbours['next']);
1365  
1366          // Normal user viewing non-grouped posts (this is only possible in visible groups).
1367          $this->setUser($user1);
1368          $_POST['group'] = 0;
1369          $this->assertEquals(0, groups_get_activity_group($cm1, true));
1370  
1371          // They can see anything in visible groups.
1372          $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1373          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1374          $this->assertEquals($disc13->id, $neighbours['next']->id);
1375          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1376          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1377          $this->assertEquals($disc14->id, $neighbours['next']->id);
1378  
1379          // Normal user, orphan of groups, can only see non-grouped posts in separate groups.
1380          $this->setUser($user2);
1381          $_POST['group'] = 0;
1382          $this->assertEquals(0, groups_get_activity_group($cm2, true));
1383  
1384          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1385          $this->assertEmpty($neighbours['prev']);
1386          $this->assertEmpty($neighbours['next']);
1387  
1388          $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1389          $this->assertEmpty($neighbours['prev']);
1390          $this->assertEquals($disc23->id, $neighbours['next']->id);
1391  
1392          $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1393          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1394          $this->assertEmpty($neighbours['next']);
1395  
1396          // Switching to viewing group 1.
1397          $this->setUser($user1);
1398          $_POST['group'] = $group1->id;
1399          $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1400          $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1401  
1402          // They can see non-grouped or same group.
1403          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1404          $this->assertEmpty($neighbours['prev']);
1405          $this->assertEquals($disc13->id, $neighbours['next']->id);
1406          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1407          $this->assertEmpty($neighbours['prev']);
1408          $this->assertEquals($disc23->id, $neighbours['next']->id);
1409  
1410          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1411          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1412          $this->assertEquals($disc15->id, $neighbours['next']->id);
1413          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1414          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1415          $this->assertEquals($disc25->id, $neighbours['next']->id);
1416  
1417          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1418          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1419          $this->assertEmpty($neighbours['next']);
1420          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1421          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1422          $this->assertEmpty($neighbours['next']);
1423  
1424          // Querying the neighbours of a discussion passing the wrong CM.
1425          $this->expectException('coding_exception');
1426          forum_get_discussion_neighbours($cm2, $disc11, $forum2);
1427      }
1428  
1429      /**
1430       * Test getting the neighbour threads of a blog-like forum with groups involved.
1431       */
1432      public function test_forum_get_neighbours_with_groups_blog() {
1433          $this->resetAfterTest();
1434  
1435          $timenow = time();
1436          $timenext = $timenow;
1437  
1438          // Setup test data.
1439          $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
1440          $course = $this->getDataGenerator()->create_course();
1441          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1442          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1443          $user1 = $this->getDataGenerator()->create_user();
1444          $user2 = $this->getDataGenerator()->create_user();
1445          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
1446          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
1447          $this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $group1->id));
1448  
1449          $forum1 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog',
1450                  'groupmode' => VISIBLEGROUPS));
1451          $forum2 = $this->getDataGenerator()->create_module('forum', array('course' => $course->id, 'type' => 'blog',
1452                  'groupmode' => SEPARATEGROUPS));
1453          $cm1 = get_coursemodule_from_instance('forum', $forum1->id);
1454          $cm2 = get_coursemodule_from_instance('forum', $forum2->id);
1455          $context1 = context_module::instance($cm1->id);
1456          $context2 = context_module::instance($cm2->id);
1457  
1458          // Creating blog posts in both forums.
1459          $record = new stdClass();
1460          $record->course = $course->id;
1461          $record->userid = $user1->id;
1462          $record->forum = $forum1->id;
1463          $record->groupid = $group1->id;
1464          $record->timemodified = time();
1465          $disc11 = $forumgen->create_discussion($record);
1466          $record->timenow = $timenext++;
1467          $record->forum = $forum2->id;
1468          $record->timemodified++;
1469          $disc21 = $forumgen->create_discussion($record);
1470  
1471          $record->timemodified++;
1472          $record->userid = $user2->id;
1473          $record->forum = $forum1->id;
1474          $record->groupid = $group2->id;
1475          $disc12 = $forumgen->create_discussion($record);
1476          $record->forum = $forum2->id;
1477          $disc22 = $forumgen->create_discussion($record);
1478  
1479          $record->timemodified++;
1480          $record->userid = $user1->id;
1481          $record->forum = $forum1->id;
1482          $record->groupid = null;
1483          $disc13 = $forumgen->create_discussion($record);
1484          $record->forum = $forum2->id;
1485          $disc23 = $forumgen->create_discussion($record);
1486  
1487          $record->timemodified++;
1488          $record->userid = $user2->id;
1489          $record->forum = $forum1->id;
1490          $record->groupid = $group2->id;
1491          $disc14 = $forumgen->create_discussion($record);
1492          $record->forum = $forum2->id;
1493          $disc24 = $forumgen->create_discussion($record);
1494  
1495          $record->timemodified++;
1496          $record->userid = $user1->id;
1497          $record->forum = $forum1->id;
1498          $record->groupid = $group1->id;
1499          $disc15 = $forumgen->create_discussion($record);
1500          $record->forum = $forum2->id;
1501          $disc25 = $forumgen->create_discussion($record);
1502  
1503          // Admin user can see all groups.
1504          $this->setAdminUser();
1505          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1506          $this->assertEmpty($neighbours['prev']);
1507          $this->assertEquals($disc12->id, $neighbours['next']->id);
1508          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1509          $this->assertEmpty($neighbours['prev']);
1510          $this->assertEquals($disc22->id, $neighbours['next']->id);
1511  
1512          $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1513          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1514          $this->assertEquals($disc13->id, $neighbours['next']->id);
1515          $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1516          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1517          $this->assertEquals($disc23->id, $neighbours['next']->id);
1518  
1519          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1520          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1521          $this->assertEquals($disc14->id, $neighbours['next']->id);
1522          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1523          $this->assertEquals($disc22->id, $neighbours['prev']->id);
1524          $this->assertEquals($disc24->id, $neighbours['next']->id);
1525  
1526          $neighbours = forum_get_discussion_neighbours($cm1, $disc14, $forum1);
1527          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1528          $this->assertEquals($disc15->id, $neighbours['next']->id);
1529          $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1530          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1531          $this->assertEquals($disc25->id, $neighbours['next']->id);
1532  
1533          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1534          $this->assertEquals($disc14->id, $neighbours['prev']->id);
1535          $this->assertEmpty($neighbours['next']);
1536          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1537          $this->assertEquals($disc24->id, $neighbours['prev']->id);
1538          $this->assertEmpty($neighbours['next']);
1539  
1540          // Admin user is only viewing group 1.
1541          $_POST['group'] = $group1->id;
1542          $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1543          $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1544  
1545          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1546          $this->assertEmpty($neighbours['prev']);
1547          $this->assertEquals($disc13->id, $neighbours['next']->id);
1548          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1549          $this->assertEmpty($neighbours['prev']);
1550          $this->assertEquals($disc23->id, $neighbours['next']->id);
1551  
1552          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1553          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1554          $this->assertEquals($disc15->id, $neighbours['next']->id);
1555          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1556          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1557          $this->assertEquals($disc25->id, $neighbours['next']->id);
1558  
1559          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1560          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1561          $this->assertEmpty($neighbours['next']);
1562          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1563          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1564          $this->assertEmpty($neighbours['next']);
1565  
1566          // Normal user viewing non-grouped posts (this is only possible in visible groups).
1567          $this->setUser($user1);
1568          $_POST['group'] = 0;
1569          $this->assertEquals(0, groups_get_activity_group($cm1, true));
1570  
1571          // They can see anything in visible groups.
1572          $neighbours = forum_get_discussion_neighbours($cm1, $disc12, $forum1);
1573          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1574          $this->assertEquals($disc13->id, $neighbours['next']->id);
1575          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1576          $this->assertEquals($disc12->id, $neighbours['prev']->id);
1577          $this->assertEquals($disc14->id, $neighbours['next']->id);
1578  
1579          // Normal user, orphan of groups, can only see non-grouped posts in separate groups.
1580          $this->setUser($user2);
1581          $_POST['group'] = 0;
1582          $this->assertEquals(0, groups_get_activity_group($cm2, true));
1583  
1584          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1585          $this->assertEmpty($neighbours['prev']);
1586          $this->assertEmpty($neighbours['next']);
1587  
1588          $neighbours = forum_get_discussion_neighbours($cm2, $disc22, $forum2);
1589          $this->assertEmpty($neighbours['prev']);
1590          $this->assertEquals($disc23->id, $neighbours['next']->id);
1591  
1592          $neighbours = forum_get_discussion_neighbours($cm2, $disc24, $forum2);
1593          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1594          $this->assertEmpty($neighbours['next']);
1595  
1596          // Switching to viewing group 1.
1597          $this->setUser($user1);
1598          $_POST['group'] = $group1->id;
1599          $this->assertEquals($group1->id, groups_get_activity_group($cm1, true));
1600          $this->assertEquals($group1->id, groups_get_activity_group($cm2, true));
1601  
1602          // They can see non-grouped or same group.
1603          $neighbours = forum_get_discussion_neighbours($cm1, $disc11, $forum1);
1604          $this->assertEmpty($neighbours['prev']);
1605          $this->assertEquals($disc13->id, $neighbours['next']->id);
1606          $neighbours = forum_get_discussion_neighbours($cm2, $disc21, $forum2);
1607          $this->assertEmpty($neighbours['prev']);
1608          $this->assertEquals($disc23->id, $neighbours['next']->id);
1609  
1610          $neighbours = forum_get_discussion_neighbours($cm1, $disc13, $forum1);
1611          $this->assertEquals($disc11->id, $neighbours['prev']->id);
1612          $this->assertEquals($disc15->id, $neighbours['next']->id);
1613          $neighbours = forum_get_discussion_neighbours($cm2, $disc23, $forum2);
1614          $this->assertEquals($disc21->id, $neighbours['prev']->id);
1615          $this->assertEquals($disc25->id, $neighbours['next']->id);
1616  
1617          $neighbours = forum_get_discussion_neighbours($cm1, $disc15, $forum1);
1618          $this->assertEquals($disc13->id, $neighbours['prev']->id);
1619          $this->assertEmpty($neighbours['next']);
1620          $neighbours = forum_get_discussion_neighbours($cm2, $disc25, $forum2);
1621          $this->assertEquals($disc23->id, $neighbours['prev']->id);
1622          $this->assertEmpty($neighbours['next']);
1623  
1624          // Querying the neighbours of a discussion passing the wrong CM.
1625          $this->expectException('coding_exception');
1626          forum_get_discussion_neighbours($cm2, $disc11, $forum2);
1627      }
1628  
1629      public function test_count_discussion_replies_basic() {
1630          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1631  
1632          // Count the discussion replies in the forum.
1633          $result = forum_count_discussion_replies($forum->id);
1634          $this->assertCount(10, $result);
1635      }
1636  
1637      public function test_count_discussion_replies_limited() {
1638          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1639          // Adding limits shouldn't make a difference.
1640          $result = forum_count_discussion_replies($forum->id, "", 20);
1641          $this->assertCount(10, $result);
1642      }
1643  
1644      public function test_count_discussion_replies_paginated() {
1645          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1646          // Adding paging shouldn't make any difference.
1647          $result = forum_count_discussion_replies($forum->id, "", -1, 0, 100);
1648          $this->assertCount(10, $result);
1649      }
1650  
1651      public function test_count_discussion_replies_paginated_sorted() {
1652          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1653          // Specifying the forumsort should also give a good result. This follows a different path.
1654          $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 100);
1655          $this->assertCount(10, $result);
1656          foreach ($result as $row) {
1657              // Grab the first discussionid.
1658              $discussionid = array_shift($discussionids);
1659              $this->assertEquals($discussionid, $row->discussion);
1660          }
1661      }
1662  
1663      public function test_count_discussion_replies_limited_sorted() {
1664          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1665          // Adding limits, and a forumsort shouldn't make a difference.
1666          $result = forum_count_discussion_replies($forum->id, "d.id asc", 20);
1667          $this->assertCount(10, $result);
1668          foreach ($result as $row) {
1669              // Grab the first discussionid.
1670              $discussionid = array_shift($discussionids);
1671              $this->assertEquals($discussionid, $row->discussion);
1672          }
1673      }
1674  
1675      public function test_count_discussion_replies_paginated_sorted_small() {
1676          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1677          // Grabbing a smaller subset and they should be ordered as expected.
1678          $result = forum_count_discussion_replies($forum->id, "d.id asc", -1, 0, 5);
1679          $this->assertCount(5, $result);
1680          foreach ($result as $row) {
1681              // Grab the first discussionid.
1682              $discussionid = array_shift($discussionids);
1683              $this->assertEquals($discussionid, $row->discussion);
1684          }
1685      }
1686  
1687      public function test_count_discussion_replies_paginated_sorted_small_reverse() {
1688          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1689          // Grabbing a smaller subset and they should be ordered as expected.
1690          $result = forum_count_discussion_replies($forum->id, "d.id desc", -1, 0, 5);
1691          $this->assertCount(5, $result);
1692          foreach ($result as $row) {
1693              // Grab the last discussionid.
1694              $discussionid = array_pop($discussionids);
1695              $this->assertEquals($discussionid, $row->discussion);
1696          }
1697      }
1698  
1699      public function test_count_discussion_replies_limited_sorted_small_reverse() {
1700          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1701          // Adding limits, and a forumsort shouldn't make a difference.
1702          $result = forum_count_discussion_replies($forum->id, "d.id desc", 5);
1703          $this->assertCount(5, $result);
1704          foreach ($result as $row) {
1705              // Grab the last discussionid.
1706              $discussionid = array_pop($discussionids);
1707              $this->assertEquals($discussionid, $row->discussion);
1708          }
1709      }
1710      public function test_discussion_pinned_sort() {
1711          list($forum, $discussionids) = $this->create_multiple_discussions_with_replies(10, 5);
1712          $cm = get_coursemodule_from_instance('forum', $forum->id);
1713          $discussions = forum_get_discussions($cm);
1714          // First discussion should be pinned.
1715          $first = reset($discussions);
1716          $this->assertEquals(1, $first->pinned, "First discussion should be pinned discussion");
1717      }
1718      public function test_forum_view() {
1719          global $CFG;
1720  
1721          $CFG->enablecompletion = 1;
1722          $this->resetAfterTest();
1723  
1724          // Setup test data.
1725          $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
1726          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id),
1727                                                              array('completion' => 2, 'completionview' => 1));
1728          $context = context_module::instance($forum->cmid);
1729          $cm = get_coursemodule_from_instance('forum', $forum->id);
1730  
1731          // Trigger and capture the event.
1732          $sink = $this->redirectEvents();
1733  
1734          $this->setAdminUser();
1735          forum_view($forum, $course, $cm, $context);
1736  
1737          $events = $sink->get_events();
1738          // 2 additional events thanks to completion.
1739          $this->assertCount(3, $events);
1740          $event = array_pop($events);
1741  
1742          // Checking that the event contains the expected values.
1743          $this->assertInstanceOf('\mod_forum\event\course_module_viewed', $event);
1744          $this->assertEquals($context, $event->get_context());
1745          $url = new \moodle_url('/mod/forum/view.php', array('f' => $forum->id));
1746          $this->assertEquals($url, $event->get_url());
1747          $this->assertEventContextNotUsed($event);
1748          $this->assertNotEmpty($event->get_name());
1749  
1750          // Check completion status.
1751          $completion = new completion_info($course);
1752          $completiondata = $completion->get_data($cm);
1753          $this->assertEquals(1, $completiondata->completionstate);
1754  
1755      }
1756  
1757      /**
1758       * Test forum_discussion_view.
1759       */
1760      public function test_forum_discussion_view() {
1761          global $CFG, $USER;
1762  
1763          $this->resetAfterTest();
1764  
1765          // Setup test data.
1766          $course = $this->getDataGenerator()->create_course();
1767          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1768          $discussion = $this->create_single_discussion_with_replies($forum, $USER, 2);
1769  
1770          $context = context_module::instance($forum->cmid);
1771          $cm = get_coursemodule_from_instance('forum', $forum->id);
1772  
1773          // Trigger and capture the event.
1774          $sink = $this->redirectEvents();
1775  
1776          $this->setAdminUser();
1777          forum_discussion_view($context, $forum, $discussion);
1778  
1779          $events = $sink->get_events();
1780          $this->assertCount(1, $events);
1781          $event = array_pop($events);
1782  
1783          // Checking that the event contains the expected values.
1784          $this->assertInstanceOf('\mod_forum\event\discussion_viewed', $event);
1785          $this->assertEquals($context, $event->get_context());
1786          $expected = array($course->id, 'forum', 'view discussion', "discuss.php?d={$discussion->id}",
1787              $discussion->id, $forum->cmid);
1788          $this->assertEventLegacyLogData($expected, $event);
1789          $this->assertEventContextNotUsed($event);
1790  
1791          $this->assertNotEmpty($event->get_name());
1792  
1793      }
1794  
1795      /**
1796       * Create a new course, forum, and user with a number of discussions and replies.
1797       *
1798       * @param int $discussioncount The number of discussions to create
1799       * @param int $replycount The number of replies to create in each discussion
1800       * @return array Containing the created forum object, and the ids of the created discussions.
1801       */
1802      protected function create_multiple_discussions_with_replies($discussioncount, $replycount) {
1803          $this->resetAfterTest();
1804  
1805          // Setup the content.
1806          $user = $this->getDataGenerator()->create_user();
1807          $course = $this->getDataGenerator()->create_course();
1808          $record = new stdClass();
1809          $record->course = $course->id;
1810          $forum = $this->getDataGenerator()->create_module('forum', $record);
1811  
1812          // Create 10 discussions with replies.
1813          $discussionids = array();
1814          for ($i = 0; $i < $discussioncount; $i++) {
1815              // Pin 3rd discussion.
1816              if ($i == 3) {
1817                  $discussion = $this->create_single_discussion_pinned_with_replies($forum, $user, $replycount);
1818              } else {
1819                  $discussion = $this->create_single_discussion_with_replies($forum, $user, $replycount);
1820              }
1821  
1822              $discussionids[] = $discussion->id;
1823          }
1824          return array($forum, $discussionids);
1825      }
1826  
1827      /**
1828       * Create a discussion with a number of replies.
1829       *
1830       * @param object $forum The forum which has been created
1831       * @param object $user The user making the discussion and replies
1832       * @param int $replycount The number of replies
1833       * @return object $discussion
1834       */
1835      protected function create_single_discussion_with_replies($forum, $user, $replycount) {
1836          global $DB;
1837  
1838          $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1839  
1840          $record = new stdClass();
1841          $record->course = $forum->course;
1842          $record->forum = $forum->id;
1843          $record->userid = $user->id;
1844          $discussion = $generator->create_discussion($record);
1845  
1846          // Retrieve the first post.
1847          $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1848  
1849          // Create the replies.
1850          $post = new stdClass();
1851          $post->userid = $user->id;
1852          $post->discussion = $discussion->id;
1853          $post->parent = $replyto->id;
1854  
1855          for ($i = 0; $i < $replycount; $i++) {
1856              $generator->create_post($post);
1857          }
1858  
1859          return $discussion;
1860      }
1861      /**
1862       * Create a discussion with a number of replies.
1863       *
1864       * @param object $forum The forum which has been created
1865       * @param object $user The user making the discussion and replies
1866       * @param int $replycount The number of replies
1867       * @return object $discussion
1868       */
1869      protected function create_single_discussion_pinned_with_replies($forum, $user, $replycount) {
1870          global $DB;
1871  
1872          $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1873  
1874          $record = new stdClass();
1875          $record->course = $forum->course;
1876          $record->forum = $forum->id;
1877          $record->userid = $user->id;
1878          $record->pinned = FORUM_DISCUSSION_PINNED;
1879          $discussion = $generator->create_discussion($record);
1880  
1881          // Retrieve the first post.
1882          $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1883  
1884          // Create the replies.
1885          $post = new stdClass();
1886          $post->userid = $user->id;
1887          $post->discussion = $discussion->id;
1888          $post->parent = $replyto->id;
1889  
1890          for ($i = 0; $i < $replycount; $i++) {
1891              $generator->create_post($post);
1892          }
1893  
1894          return $discussion;
1895      }
1896  
1897      /**
1898       * Tests for mod_forum_rating_can_see_item_ratings().
1899       *
1900       * @throws coding_exception
1901       * @throws rating_exception
1902       */
1903      public function test_mod_forum_rating_can_see_item_ratings() {
1904          global $DB;
1905  
1906          $this->resetAfterTest();
1907  
1908          // Setup test data.
1909          $course = new stdClass();
1910          $course->groupmode = SEPARATEGROUPS;
1911          $course->groupmodeforce = true;
1912          $course = $this->getDataGenerator()->create_course($course);
1913          $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
1914          $generator = self::getDataGenerator()->get_plugin_generator('mod_forum');
1915          $cm = get_coursemodule_from_instance('forum', $forum->id);
1916          $context = context_module::instance($cm->id);
1917  
1918          // Create users.
1919          $user1 = $this->getDataGenerator()->create_user();
1920          $user2 = $this->getDataGenerator()->create_user();
1921          $user3 = $this->getDataGenerator()->create_user();
1922          $user4 = $this->getDataGenerator()->create_user();
1923  
1924          // Groups and stuff.
1925          $role = $DB->get_record('role', array('shortname' => 'teacher'), '*', MUST_EXIST);
1926          $this->getDataGenerator()->enrol_user($user1->id, $course->id, $role->id);
1927          $this->getDataGenerator()->enrol_user($user2->id, $course->id, $role->id);
1928          $this->getDataGenerator()->enrol_user($user3->id, $course->id, $role->id);
1929          $this->getDataGenerator()->enrol_user($user4->id, $course->id, $role->id);
1930  
1931          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1932          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
1933          groups_add_member($group1, $user1);
1934          groups_add_member($group1, $user2);
1935          groups_add_member($group2, $user3);
1936          groups_add_member($group2, $user4);
1937  
1938          $record = new stdClass();
1939          $record->course = $forum->course;
1940          $record->forum = $forum->id;
1941          $record->userid = $user1->id;
1942          $record->groupid = $group1->id;
1943          $discussion = $generator->create_discussion($record);
1944  
1945          // Retrieve the first post.
1946          $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
1947  
1948          $ratingoptions = new stdClass;
1949          $ratingoptions->context = $context;
1950          $ratingoptions->ratingarea = 'post';
1951          $ratingoptions->component = 'mod_forum';
1952          $ratingoptions->itemid  = $post->id;
1953          $ratingoptions->scaleid = 2;
1954          $ratingoptions->userid  = $user2->id;
1955          $rating = new rating($ratingoptions);
1956          $rating->update_rating(2);
1957  
1958          // Now try to access it as various users.
1959          unassign_capability('moodle/site:accessallgroups', $role->id);
1960          $params = array('contextid' => 2,
1961                          'component' => 'mod_forum',
1962                          'ratingarea' => 'post',
1963                          'itemid' => $post->id,
1964                          'scaleid' => 2);
1965          $this->setUser($user1);
1966          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1967          $this->setUser($user2);
1968          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1969          $this->setUser($user3);
1970          $this->assertFalse(mod_forum_rating_can_see_item_ratings($params));
1971          $this->setUser($user4);
1972          $this->assertFalse(mod_forum_rating_can_see_item_ratings($params));
1973  
1974          // Now try with accessallgroups cap and make sure everything is visible.
1975          assign_capability('moodle/site:accessallgroups', CAP_ALLOW, $role->id, $context->id);
1976          $this->setUser($user1);
1977          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1978          $this->setUser($user2);
1979          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1980          $this->setUser($user3);
1981          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1982          $this->setUser($user4);
1983          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1984  
1985          // Change group mode and verify visibility.
1986          $course->groupmode = VISIBLEGROUPS;
1987          $DB->update_record('course', $course);
1988          unassign_capability('moodle/site:accessallgroups', $role->id);
1989          $this->setUser($user1);
1990          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1991          $this->setUser($user2);
1992          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1993          $this->setUser($user3);
1994          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1995          $this->setUser($user4);
1996          $this->assertTrue(mod_forum_rating_can_see_item_ratings($params));
1997  
1998      }
1999  
2000      /**
2001       * Test forum_get_discussions
2002       */
2003      public function test_forum_get_discussions_with_groups() {
2004          global $DB;
2005  
2006          $this->resetAfterTest(true);
2007  
2008          // Create course to add the module.
2009          $course = self::getDataGenerator()->create_course(array('groupmode' => VISIBLEGROUPS, 'groupmodeforce' => 0));
2010          $user1 = self::getDataGenerator()->create_user();
2011          $user2 = self::getDataGenerator()->create_user();
2012          $user3 = self::getDataGenerator()->create_user();
2013  
2014          $role = $DB->get_record('role', array('shortname' => 'student'), '*', MUST_EXIST);
2015          self::getDataGenerator()->enrol_user($user1->id, $course->id, $role->id);
2016          self::getDataGenerator()->enrol_user($user2->id, $course->id, $role->id);
2017          self::getDataGenerator()->enrol_user($user3->id, $course->id, $role->id);
2018  
2019          // Forum forcing separate gropus.
2020          $record = new stdClass();
2021          $record->course = $course->id;
2022          $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
2023          $cm = get_coursemodule_from_instance('forum', $forum->id);
2024  
2025          // Create groups.
2026          $group1 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
2027          $group2 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
2028          $group3 = self::getDataGenerator()->create_group(array('courseid' => $course->id));
2029  
2030          // Add the user1 to g1 and g2 groups.
2031          groups_add_member($group1->id, $user1->id);
2032          groups_add_member($group2->id, $user1->id);
2033  
2034          // Add the user 2 and 3 to only one group.
2035          groups_add_member($group1->id, $user2->id);
2036          groups_add_member($group3->id, $user3->id);
2037  
2038          // Add a few discussions.
2039          $record = array();
2040          $record['course'] = $course->id;
2041          $record['forum'] = $forum->id;
2042          $record['userid'] = $user1->id;
2043          $record['groupid'] = $group1->id;
2044          $discussiong1u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2045  
2046          $record['groupid'] = $group2->id;
2047          $discussiong2u1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2048  
2049          $record['userid'] = $user2->id;
2050          $record['groupid'] = $group1->id;
2051          $discussiong1u2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2052  
2053          $record['userid'] = $user3->id;
2054          $record['groupid'] = $group3->id;
2055          $discussiong3u3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2056  
2057          self::setUser($user1);
2058          // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions.
2059          $discussions = forum_get_discussions($cm);
2060          self::assertCount(2, $discussions);
2061          foreach ($discussions as $discussion) {
2062              self::assertEquals($group1->id, $discussion->groupid);
2063          }
2064  
2065          // Get all my discussions.
2066          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0);
2067          self::assertCount(3, $discussions);
2068  
2069          // Get all my g1 discussions.
2070          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group1->id);
2071          self::assertCount(2, $discussions);
2072          foreach ($discussions as $discussion) {
2073              self::assertEquals($group1->id, $discussion->groupid);
2074          }
2075  
2076          // Get all my g2 discussions.
2077          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id);
2078          self::assertCount(1, $discussions);
2079          $discussion = array_shift($discussions);
2080          self::assertEquals($group2->id, $discussion->groupid);
2081          self::assertEquals($user1->id, $discussion->userid);
2082          self::assertEquals($discussiong2u1->id, $discussion->discussion);
2083  
2084          // Get all my g3 discussions (I'm not enrolled in that group).
2085          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id);
2086          self::assertCount(0, $discussions);
2087  
2088          // This group does not exist.
2089          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id + 1000);
2090          self::assertCount(0, $discussions);
2091  
2092          self::setUser($user2);
2093  
2094          // Test retrieve discussions not passing the groupid parameter. We will receive only first group discussions.
2095          $discussions = forum_get_discussions($cm);
2096          self::assertCount(2, $discussions);
2097          foreach ($discussions as $discussion) {
2098              self::assertEquals($group1->id, $discussion->groupid);
2099          }
2100  
2101          // Get all my viewable discussions.
2102          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, 0);
2103          self::assertCount(2, $discussions);
2104          foreach ($discussions as $discussion) {
2105              self::assertEquals($group1->id, $discussion->groupid);
2106          }
2107  
2108          // Get all my g2 discussions (I'm not enrolled in that group).
2109          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group2->id);
2110          self::assertCount(0, $discussions);
2111  
2112          // Get all my g3 discussions (I'm not enrolled in that group).
2113          $discussions = forum_get_discussions($cm, '', true, -1, -1, false, -1, 0, $group3->id);
2114          self::assertCount(0, $discussions);
2115  
2116      }
2117  
2118      /**
2119       * Test forum_user_can_post_discussion
2120       */
2121      public function test_forum_user_can_post_discussion() {
2122          global $CFG, $DB;
2123  
2124          $this->resetAfterTest(true);
2125  
2126          // Create course to add the module.
2127          $course = self::getDataGenerator()->create_course(array('groupmode' => SEPARATEGROUPS, 'groupmodeforce' => 1));
2128          $user = self::getDataGenerator()->create_user();
2129          $this->getDataGenerator()->enrol_user($user->id, $course->id);
2130  
2131          // Forum forcing separate gropus.
2132          $record = new stdClass();
2133          $record->course = $course->id;
2134          $forum = self::getDataGenerator()->create_module('forum', $record, array('groupmode' => SEPARATEGROUPS));
2135          $cm = get_coursemodule_from_instance('forum', $forum->id);
2136          $context = context_module::instance($cm->id);
2137  
2138          self::setUser($user);
2139  
2140          // The user is not enroled in any group, try to post in a forum with separate groups.
2141          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2142          $this->assertFalse($can);
2143  
2144          // Create a group.
2145          $group = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2146  
2147          // Try to post in a group the user is not enrolled.
2148          $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context);
2149          $this->assertFalse($can);
2150  
2151          // Add the user to a group.
2152          groups_add_member($group->id, $user->id);
2153  
2154          // Try to post in a group the user is not enrolled.
2155          $can = forum_user_can_post_discussion($forum, $group->id + 1, -1, $cm, $context);
2156          $this->assertFalse($can);
2157  
2158          // Now try to post in the user group. (null means it will guess the group).
2159          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2160          $this->assertTrue($can);
2161  
2162          $can = forum_user_can_post_discussion($forum, $group->id, -1, $cm, $context);
2163          $this->assertTrue($can);
2164  
2165          // Test all groups.
2166          $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context);
2167          $this->assertFalse($can);
2168  
2169          $this->setAdminUser();
2170          $can = forum_user_can_post_discussion($forum, -1, -1, $cm, $context);
2171          $this->assertTrue($can);
2172  
2173          // Change forum type.
2174          $forum->type = 'news';
2175          $DB->update_record('forum', $forum);
2176  
2177          // Admin can post news.
2178          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2179          $this->assertTrue($can);
2180  
2181          // Normal users don't.
2182          self::setUser($user);
2183          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2184          $this->assertFalse($can);
2185  
2186          // Change forum type.
2187          $forum->type = 'eachuser';
2188          $DB->update_record('forum', $forum);
2189  
2190          // I didn't post yet, so I should be able to post.
2191          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2192          $this->assertTrue($can);
2193  
2194          // Post now.
2195          $record = new stdClass();
2196          $record->course = $course->id;
2197          $record->userid = $user->id;
2198          $record->forum = $forum->id;
2199          $record->groupid = $group->id;
2200          $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2201  
2202          // I already posted, I shouldn't be able to post.
2203          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2204          $this->assertFalse($can);
2205  
2206          // Last check with no groups, normal forum and course.
2207          $course->groupmode = NOGROUPS;
2208          $course->groupmodeforce = 0;
2209          $DB->update_record('course', $course);
2210  
2211          $forum->type = 'general';
2212          $forum->groupmode = NOGROUPS;
2213          $DB->update_record('forum', $forum);
2214  
2215          $can = forum_user_can_post_discussion($forum, null, -1, $cm, $context);
2216          $this->assertTrue($can);
2217      }
2218  
2219      /**
2220       * Test forum_user_has_posted_discussion with no groups.
2221       */
2222      public function test_forum_user_has_posted_discussion_no_groups() {
2223          global $CFG;
2224  
2225          $this->resetAfterTest(true);
2226  
2227          $course = self::getDataGenerator()->create_course();
2228          $author = self::getDataGenerator()->create_user();
2229          $other = self::getDataGenerator()->create_user();
2230          $this->getDataGenerator()->enrol_user($author->id, $course->id);
2231          $forum = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]);
2232  
2233          self::setUser($author);
2234  
2235          // Neither user has posted.
2236          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id));
2237          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $other->id));
2238  
2239          // Post in the forum.
2240          $record = new stdClass();
2241          $record->course = $course->id;
2242          $record->userid = $author->id;
2243          $record->forum = $forum->id;
2244          $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2245  
2246          // The author has now posted, but the other user has not.
2247          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id));
2248          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $other->id));
2249      }
2250  
2251      /**
2252       * Test forum_user_has_posted_discussion with multiple forums
2253       */
2254      public function test_forum_user_has_posted_discussion_multiple_forums() {
2255          global $CFG;
2256  
2257          $this->resetAfterTest(true);
2258  
2259          $course = self::getDataGenerator()->create_course();
2260          $author = self::getDataGenerator()->create_user();
2261          $this->getDataGenerator()->enrol_user($author->id, $course->id);
2262          $forum1 = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]);
2263          $forum2 = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ]);
2264  
2265          self::setUser($author);
2266  
2267          // No post in either forum.
2268          $this->assertFalse(forum_user_has_posted_discussion($forum1->id, $author->id));
2269          $this->assertFalse(forum_user_has_posted_discussion($forum2->id, $author->id));
2270  
2271          // Post in the forum.
2272          $record = new stdClass();
2273          $record->course = $course->id;
2274          $record->userid = $author->id;
2275          $record->forum = $forum1->id;
2276          $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2277  
2278          // The author has now posted in forum1, but not forum2.
2279          $this->assertTrue(forum_user_has_posted_discussion($forum1->id, $author->id));
2280          $this->assertFalse(forum_user_has_posted_discussion($forum2->id, $author->id));
2281      }
2282  
2283      /**
2284       * Test forum_user_has_posted_discussion with multiple groups.
2285       */
2286      public function test_forum_user_has_posted_discussion_multiple_groups() {
2287          global $CFG;
2288  
2289          $this->resetAfterTest(true);
2290  
2291          $course = self::getDataGenerator()->create_course();
2292          $author = self::getDataGenerator()->create_user();
2293          $this->getDataGenerator()->enrol_user($author->id, $course->id);
2294  
2295          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2296          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
2297          groups_add_member($group1->id, $author->id);
2298          groups_add_member($group2->id, $author->id);
2299  
2300          $forum = self::getDataGenerator()->create_module('forum', (object) ['course' => $course->id ], [
2301                      'groupmode' => SEPARATEGROUPS,
2302                  ]);
2303  
2304          self::setUser($author);
2305  
2306          // The user has not posted in either group.
2307          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id));
2308          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id));
2309          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id));
2310  
2311          // Post in one group.
2312          $record = new stdClass();
2313          $record->course = $course->id;
2314          $record->userid = $author->id;
2315          $record->forum = $forum->id;
2316          $record->groupid = $group1->id;
2317          $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2318  
2319          // The author has now posted in one group, but the other user has not.
2320          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id));
2321          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id));
2322          $this->assertFalse(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id));
2323  
2324          // Post in the other group.
2325          $record = new stdClass();
2326          $record->course = $course->id;
2327          $record->userid = $author->id;
2328          $record->forum = $forum->id;
2329          $record->groupid = $group2->id;
2330          $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2331  
2332          // The author has now posted in one group, but the other user has not.
2333          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id));
2334          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group1->id));
2335          $this->assertTrue(forum_user_has_posted_discussion($forum->id, $author->id, $group2->id));
2336      }
2337  
2338      /**
2339       * Tests the mod_forum_myprofile_navigation() function.
2340       */
2341      public function test_mod_forum_myprofile_navigation() {
2342          $this->resetAfterTest(true);
2343  
2344          // Set up the test.
2345          $tree = new \core_user\output\myprofile\tree();
2346          $user = $this->getDataGenerator()->create_user();
2347          $course = $this->getDataGenerator()->create_course();
2348          $iscurrentuser = true;
2349  
2350          // Set as the current user.
2351          $this->setUser($user);
2352  
2353          // Check the node tree is correct.
2354          mod_forum_myprofile_navigation($tree, $user, $iscurrentuser, $course);
2355          $reflector = new ReflectionObject($tree);
2356          $nodes = $reflector->getProperty('nodes');
2357          $nodes->setAccessible(true);
2358          $this->assertArrayHasKey('forumposts', $nodes->getValue($tree));
2359          $this->assertArrayHasKey('forumdiscussions', $nodes->getValue($tree));
2360      }
2361  
2362      /**
2363       * Tests the mod_forum_myprofile_navigation() function as a guest.
2364       */
2365      public function test_mod_forum_myprofile_navigation_as_guest() {
2366          global $USER;
2367  
2368          $this->resetAfterTest(true);
2369  
2370          // Set up the test.
2371          $tree = new \core_user\output\myprofile\tree();
2372          $course = $this->getDataGenerator()->create_course();
2373          $iscurrentuser = true;
2374  
2375          // Set user as guest.
2376          $this->setGuestUser();
2377  
2378          // Check the node tree is correct.
2379          mod_forum_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
2380          $reflector = new ReflectionObject($tree);
2381          $nodes = $reflector->getProperty('nodes');
2382          $nodes->setAccessible(true);
2383          $this->assertArrayNotHasKey('forumposts', $nodes->getValue($tree));
2384          $this->assertArrayNotHasKey('forumdiscussions', $nodes->getValue($tree));
2385      }
2386  
2387      /**
2388       * Tests the mod_forum_myprofile_navigation() function as a user viewing another user's profile.
2389       */
2390      public function test_mod_forum_myprofile_navigation_different_user() {
2391          $this->resetAfterTest(true);
2392  
2393          // Set up the test.
2394          $tree = new \core_user\output\myprofile\tree();
2395          $user = $this->getDataGenerator()->create_user();
2396          $user2 = $this->getDataGenerator()->create_user();
2397          $course = $this->getDataGenerator()->create_course();
2398          $iscurrentuser = true;
2399  
2400          // Set to different user's profile.
2401          $this->setUser($user2);
2402  
2403          // Check the node tree is correct.
2404          mod_forum_myprofile_navigation($tree, $user, $iscurrentuser, $course);
2405          $reflector = new ReflectionObject($tree);
2406          $nodes = $reflector->getProperty('nodes');
2407          $nodes->setAccessible(true);
2408          $this->assertArrayHasKey('forumposts', $nodes->getValue($tree));
2409          $this->assertArrayHasKey('forumdiscussions', $nodes->getValue($tree));
2410      }
2411  
2412      public function test_print_overview() {
2413          $this->resetAfterTest();
2414          $course1 = self::getDataGenerator()->create_course();
2415          $course2 = self::getDataGenerator()->create_course();
2416  
2417          // Create an author user.
2418          $author = self::getDataGenerator()->create_user();
2419          $this->getDataGenerator()->enrol_user($author->id, $course1->id);
2420          $this->getDataGenerator()->enrol_user($author->id, $course2->id);
2421  
2422          // Create a viewer user.
2423          $viewer = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2424          $this->getDataGenerator()->enrol_user($viewer->id, $course1->id);
2425          $this->getDataGenerator()->enrol_user($viewer->id, $course2->id);
2426  
2427          // Create two forums - one in each course.
2428          $record = new stdClass();
2429          $record->course = $course1->id;
2430          $forum1 = self::getDataGenerator()->create_module('forum', (object) array('course' => $course1->id));
2431          $forum2 = self::getDataGenerator()->create_module('forum', (object) array('course' => $course2->id));
2432  
2433          // A standard post in the forum.
2434          $record = new stdClass();
2435          $record->course = $course1->id;
2436          $record->userid = $author->id;
2437          $record->forum = $forum1->id;
2438          $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2439  
2440          $this->setUser($viewer->id);
2441          $courses = array(
2442              $course1->id => clone $course1,
2443              $course2->id => clone $course2,
2444          );
2445  
2446          foreach ($courses as $courseid => $course) {
2447              $courses[$courseid]->lastaccess = 0;
2448          }
2449          $results = array();
2450          forum_print_overview($courses, $results);
2451  
2452          // There should be one entry for course1, and no others.
2453          $this->assertCount(1, $results);
2454  
2455          // There should be one entry for a forum in course1.
2456          $this->assertCount(1, $results[$course1->id]);
2457          $this->assertArrayHasKey('forum', $results[$course1->id]);
2458      }
2459  
2460      public function test_print_overview_groups() {
2461          $this->resetAfterTest();
2462          $course1 = self::getDataGenerator()->create_course();
2463          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
2464          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
2465  
2466          // Create an author user.
2467          $author = self::getDataGenerator()->create_user();
2468          $this->getDataGenerator()->enrol_user($author->id, $course1->id);
2469  
2470          // Create two viewer users - one in each group.
2471          $viewer1 = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2472          $this->getDataGenerator()->enrol_user($viewer1->id, $course1->id);
2473          $this->getDataGenerator()->create_group_member(array('userid' => $viewer1->id, 'groupid' => $group1->id));
2474  
2475          $viewer2 = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2476          $this->getDataGenerator()->enrol_user($viewer2->id, $course1->id);
2477          $this->getDataGenerator()->create_group_member(array('userid' => $viewer2->id, 'groupid' => $group2->id));
2478  
2479          // Create a forum.
2480          $record = new stdClass();
2481          $record->course = $course1->id;
2482          $forum1 = self::getDataGenerator()->create_module('forum', (object) array(
2483              'course'        => $course1->id,
2484              'groupmode'     => SEPARATEGROUPS,
2485          ));
2486  
2487          // A post in the forum for group1.
2488          $record = new stdClass();
2489          $record->course     = $course1->id;
2490          $record->userid     = $author->id;
2491          $record->forum      = $forum1->id;
2492          $record->groupid    = $group1->id;
2493          $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2494  
2495          $course1->lastaccess = 0;
2496          $courses = array($course1->id => $course1);
2497  
2498          // As viewer1 (same group as post).
2499          $this->setUser($viewer1->id);
2500          $results = array();
2501          forum_print_overview($courses, $results);
2502  
2503          // There should be one entry for course1.
2504          $this->assertCount(1, $results);
2505  
2506          // There should be one entry for a forum in course1.
2507          $this->assertCount(1, $results[$course1->id]);
2508          $this->assertArrayHasKey('forum', $results[$course1->id]);
2509  
2510          $this->setUser($viewer2->id);
2511          $results = array();
2512          forum_print_overview($courses, $results);
2513  
2514          // There should be one entry for course1.
2515          $this->assertCount(0, $results);
2516      }
2517  
2518      /**
2519       * @dataProvider print_overview_timed_provider
2520       */
2521      public function test_print_overview_timed($config, $hasresult) {
2522          $this->resetAfterTest();
2523          $course1 = self::getDataGenerator()->create_course();
2524  
2525          // Create an author user.
2526          $author = self::getDataGenerator()->create_user();
2527          $this->getDataGenerator()->enrol_user($author->id, $course1->id);
2528  
2529          // Create a viewer user.
2530          $viewer = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2531          $this->getDataGenerator()->enrol_user($viewer->id, $course1->id);
2532  
2533          // Create a forum.
2534          $record = new stdClass();
2535          $record->course = $course1->id;
2536          $forum1 = self::getDataGenerator()->create_module('forum', (object) array('course' => $course1->id));
2537  
2538          // A timed post with a timestart in the past (24 hours ago).
2539          $record = new stdClass();
2540          $record->course = $course1->id;
2541          $record->userid = $author->id;
2542          $record->forum = $forum1->id;
2543          if (isset($config['timestartmodifier'])) {
2544              $record->timestart = time() + $config['timestartmodifier'];
2545          }
2546          if (isset($config['timeendmodifier'])) {
2547              $record->timeend = time() + $config['timeendmodifier'];
2548          }
2549          $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2550  
2551          $course1->lastaccess = 0;
2552          $courses = array($course1->id => $course1);
2553  
2554          // As viewer, check the forum_print_overview result.
2555          $this->setUser($viewer->id);
2556          $results = array();
2557          forum_print_overview($courses, $results);
2558  
2559          if ($hasresult) {
2560              // There should be one entry for course1.
2561              $this->assertCount(1, $results);
2562  
2563              // There should be one entry for a forum in course1.
2564              $this->assertCount(1, $results[$course1->id]);
2565              $this->assertArrayHasKey('forum', $results[$course1->id]);
2566          } else {
2567              // There should be no entries for any course.
2568              $this->assertCount(0, $results);
2569          }
2570      }
2571  
2572      /**
2573       * @dataProvider print_overview_timed_provider
2574       */
2575      public function test_print_overview_timed_groups($config, $hasresult) {
2576          $this->resetAfterTest();
2577          $course1 = self::getDataGenerator()->create_course();
2578          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
2579          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
2580  
2581          // Create an author user.
2582          $author = self::getDataGenerator()->create_user();
2583          $this->getDataGenerator()->enrol_user($author->id, $course1->id);
2584  
2585          // Create two viewer users - one in each group.
2586          $viewer1 = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2587          $this->getDataGenerator()->enrol_user($viewer1->id, $course1->id);
2588          $this->getDataGenerator()->create_group_member(array('userid' => $viewer1->id, 'groupid' => $group1->id));
2589  
2590          $viewer2 = self::getDataGenerator()->create_user((object) array('trackforums' => 1));
2591          $this->getDataGenerator()->enrol_user($viewer2->id, $course1->id);
2592          $this->getDataGenerator()->create_group_member(array('userid' => $viewer2->id, 'groupid' => $group2->id));
2593  
2594          // Create a forum.
2595          $record = new stdClass();
2596          $record->course = $course1->id;
2597          $forum1 = self::getDataGenerator()->create_module('forum', (object) array(
2598              'course'        => $course1->id,
2599              'groupmode'     => SEPARATEGROUPS,
2600          ));
2601  
2602          // A post in the forum for group1.
2603          $record = new stdClass();
2604          $record->course     = $course1->id;
2605          $record->userid     = $author->id;
2606          $record->forum      = $forum1->id;
2607          $record->groupid    = $group1->id;
2608          if (isset($config['timestartmodifier'])) {
2609              $record->timestart = time() + $config['timestartmodifier'];
2610          }
2611          if (isset($config['timeendmodifier'])) {
2612              $record->timeend = time() + $config['timeendmodifier'];
2613          }
2614          $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record);
2615  
2616          $course1->lastaccess = 0;
2617          $courses = array($course1->id => $course1);
2618  
2619          // As viewer1 (same group as post).
2620          $this->setUser($viewer1->id);
2621          $results = array();
2622          forum_print_overview($courses, $results);
2623  
2624          if ($hasresult) {
2625              // There should be one entry for course1.
2626              $this->assertCount(1, $results);
2627  
2628              // There should be one entry for a forum in course1.
2629              $this->assertCount(1, $results[$course1->id]);
2630              $this->assertArrayHasKey('forum', $results[$course1->id]);
2631          } else {
2632              // There should be no entries for any course.
2633              $this->assertCount(0, $results);
2634          }
2635  
2636          $this->setUser($viewer2->id);
2637          $results = array();
2638          forum_print_overview($courses, $results);
2639  
2640          // There should be one entry for course1.
2641          $this->assertCount(0, $results);
2642      }
2643  
2644      public function print_overview_timed_provider() {
2645          return array(
2646              'timestart_past' => array(
2647                  'discussionconfig' => array(
2648                      'timestartmodifier' => -86000,
2649                  ),
2650                  'hasresult'         => true,
2651              ),
2652              'timestart_future' => array(
2653                  'discussionconfig' => array(
2654                      'timestartmodifier' => 86000,
2655                  ),
2656                  'hasresult'         => false,
2657              ),
2658              'timeend_past' => array(
2659                  'discussionconfig' => array(
2660                      'timeendmodifier'   => -86000,
2661                  ),
2662                  'hasresult'         => false,
2663              ),
2664              'timeend_future' => array(
2665                  'discussionconfig' => array(
2666                      'timeendmodifier'   => 86000,
2667                  ),
2668                  'hasresult'         => true,
2669              ),
2670          );
2671      }
2672  
2673      /**
2674       * Test test_pinned_discussion_with_group.
2675       */
2676      public function test_pinned_discussion_with_group() {
2677          global $SESSION;
2678  
2679          $this->resetAfterTest();
2680          $course1 = $this->getDataGenerator()->create_course();
2681          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id));
2682  
2683          // Create an author user.
2684          $author = $this->getDataGenerator()->create_user();
2685          $this->getDataGenerator()->enrol_user($author->id, $course1->id);
2686  
2687          // Create two viewer users - one in a group, one not.
2688          $viewer1 = $this->getDataGenerator()->create_user((object) array('trackforums' => 1));
2689          $this->getDataGenerator()->enrol_user($viewer1->id, $course1->id);
2690  
2691          $viewer2 = $this->getDataGenerator()->create_user((object) array('trackforums' => 1));
2692          $this->getDataGenerator()->enrol_user($viewer2->id, $course1->id);
2693          $this->getDataGenerator()->create_group_member(array('userid' => $viewer2->id, 'groupid' => $group1->id));
2694  
2695          $forum1 = $this->getDataGenerator()->create_module('forum', (object) array(
2696              'course' => $course1->id,
2697              'groupmode' => SEPARATEGROUPS,
2698          ));
2699  
2700          $coursemodule = get_coursemodule_from_instance('forum', $forum1->id);
2701  
2702          $alldiscussions = array();
2703          $group1discussions = array();
2704  
2705          // Create 4 discussions in all participants group and group1, where the first
2706          // discussion is pinned in each group.
2707          $allrecord = new stdClass();
2708          $allrecord->course = $course1->id;
2709          $allrecord->userid = $author->id;
2710          $allrecord->forum = $forum1->id;
2711          $allrecord->pinned = FORUM_DISCUSSION_PINNED;
2712  
2713          $group1record = new stdClass();
2714          $group1record->course = $course1->id;
2715          $group1record->userid = $author->id;
2716          $group1record->forum = $forum1->id;
2717          $group1record->groupid = $group1->id;
2718          $group1record->pinned = FORUM_DISCUSSION_PINNED;
2719  
2720          $alldiscussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($allrecord);
2721          $group1discussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($group1record);
2722  
2723          // Create unpinned discussions.
2724          $allrecord->pinned = FORUM_DISCUSSION_UNPINNED;
2725          $group1record->pinned = FORUM_DISCUSSION_UNPINNED;
2726          for ($i = 0; $i < 3; $i++) {
2727              $alldiscussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($allrecord);
2728              $group1discussions[] = $this->getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($group1record);
2729          }
2730  
2731          // As viewer1 (no group). This user shouldn't see any of group1's discussions
2732          // so their expected discussion order is (where rightmost is highest priority):
2733          // Ad1, ad2, ad3, ad0.
2734          $this->setUser($viewer1->id);
2735  
2736          // CHECK 1.
2737          // Take the neighbours of ad3, which should be prev: ad2 and next: ad0.
2738          $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[3], $forum1);
2739          // Ad2 check.
2740          $this->assertEquals($alldiscussions[2]->id, $neighbours['prev']->id);
2741          // Ad0 check.
2742          $this->assertEquals($alldiscussions[0]->id, $neighbours['next']->id);
2743  
2744          // CHECK 2.
2745          // Take the neighbours of ad0, which should be prev: ad3 and next: null.
2746          $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[0], $forum1);
2747          // Ad3 check.
2748          $this->assertEquals($alldiscussions[3]->id, $neighbours['prev']->id);
2749          // Null check.
2750          $this->assertEmpty($neighbours['next']);
2751  
2752          // CHECK 3.
2753          // Take the neighbours of ad1, which should be prev: null and next: ad2.
2754          $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[1], $forum1);
2755          // Null check.
2756          $this->assertEmpty($neighbours['prev']);
2757          // Ad2 check.
2758          $this->assertEquals($alldiscussions[2]->id, $neighbours['next']->id);
2759  
2760          // Temporary hack to workaround for MDL-52656.
2761          $SESSION->currentgroup = null;
2762  
2763          // As viewer2 (group1). This user should see all of group1's posts and the all participants group.
2764          // The expected discussion order is (rightmost is highest priority):
2765          // Ad1, gd1, ad2, gd2, ad3, gd3, ad0, gd0.
2766          $this->setUser($viewer2->id);
2767  
2768          // CHECK 1.
2769          // Take the neighbours of ad1, which should be prev: null and next: gd1.
2770          $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[1], $forum1);
2771          // Null check.
2772          $this->assertEmpty($neighbours['prev']);
2773          // Gd1 check.
2774          $this->assertEquals($group1discussions[1]->id, $neighbours['next']->id);
2775  
2776          // CHECK 2.
2777          // Take the neighbours of ad3, which should be prev: gd2 and next: gd3.
2778          $neighbours = forum_get_discussion_neighbours($coursemodule, $alldiscussions[3], $forum1);
2779          // Gd2 check.
2780          $this->assertEquals($group1discussions[2]->id, $neighbours['prev']->id);
2781          // Gd3 check.
2782          $this->assertEquals($group1discussions[3]->id, $neighbours['next']->id);
2783  
2784          // CHECK 3.
2785          // Take the neighbours of gd3, which should be prev: ad3 and next: ad0.
2786          $neighbours = forum_get_discussion_neighbours($coursemodule, $group1discussions[3], $forum1);
2787          // Ad3 check.
2788          $this->assertEquals($alldiscussions[3]->id, $neighbours['prev']->id);
2789          // Ad0 check.
2790          $this->assertEquals($alldiscussions[0]->id, $neighbours['next']->id);
2791  
2792          // CHECK 4.
2793          // Take the neighbours of gd0, which should be prev: ad0 and next: null.
2794          $neighbours = forum_get_discussion_neighbours($coursemodule, $group1discussions[0], $forum1);
2795          // Ad0 check.
2796          $this->assertEquals($alldiscussions[0]->id, $neighbours['prev']->id);
2797          // Null check.
2798          $this->assertEmpty($neighbours['next']);
2799      }
2800  
2801      /**
2802       * Test test_pinned_with_timed_discussions.
2803       */
2804      public function test_pinned_with_timed_discussions() {
2805          global $CFG;
2806  
2807          $CFG->forum_enabletimedposts = true;
2808  
2809          $this->resetAfterTest();
2810          $course = $this->getDataGenerator()->create_course();
2811  
2812          // Create an user.
2813          $user = $this->getDataGenerator()->create_user();
2814          $this->getDataGenerator()->enrol_user($user->id, $course->id);
2815  
2816          // Create a forum.
2817          $record = new stdClass();
2818          $record->course = $course->id;
2819          $forum = $this->getDataGenerator()->create_module('forum', (object) array(
2820              'course' => $course->id,
2821              'groupmode' => SEPARATEGROUPS,
2822          ));
2823  
2824          $coursemodule = get_coursemodule_from_instance('forum', $forum->id);
2825          $now = time();
2826          $discussions = array();
2827          $discussiongenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
2828  
2829          $record = new stdClass();
2830          $record->course = $course->id;
2831          $record->userid = $user->id;
2832          $record->forum = $forum->id;
2833          $record->pinned = FORUM_DISCUSSION_PINNED;
2834          $record->timemodified = $now;
2835  
2836          $discussions[] = $discussiongenerator->create_discussion($record);
2837  
2838          $record->pinned = FORUM_DISCUSSION_UNPINNED;
2839          $record->timestart = $now + 10;
2840  
2841          $discussions[] = $discussiongenerator->create_discussion($record);
2842  
2843          $record->timestart = $now;
2844  
2845          $discussions[] = $discussiongenerator->create_discussion($record);
2846  
2847          // Expected order of discussions:
2848          // D2, d1, d0.
2849          $this->setUser($user->id);
2850  
2851          // CHECK 1.
2852          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[2], $forum);
2853          // Null check.
2854          $this->assertEmpty($neighbours['prev']);
2855          // D1 check.
2856          $this->assertEquals($discussions[1]->id, $neighbours['next']->id);
2857  
2858          // CHECK 2.
2859          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[1], $forum);
2860          // D2 check.
2861          $this->assertEquals($discussions[2]->id, $neighbours['prev']->id);
2862          // D0 check.
2863          $this->assertEquals($discussions[0]->id, $neighbours['next']->id);
2864  
2865          // CHECK 3.
2866          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[0], $forum);
2867          // D2 check.
2868          $this->assertEquals($discussions[1]->id, $neighbours['prev']->id);
2869          // Null check.
2870          $this->assertEmpty($neighbours['next']);
2871      }
2872  
2873      /**
2874       * Test test_pinned_timed_discussions_with_timed_discussions.
2875       */
2876      public function test_pinned_timed_discussions_with_timed_discussions() {
2877          global $CFG;
2878  
2879          $CFG->forum_enabletimedposts = true;
2880  
2881          $this->resetAfterTest();
2882          $course = $this->getDataGenerator()->create_course();
2883  
2884          // Create an user.
2885          $user = $this->getDataGenerator()->create_user();
2886          $this->getDataGenerator()->enrol_user($user->id, $course->id);
2887  
2888          // Create a forum.
2889          $record = new stdClass();
2890          $record->course = $course->id;
2891          $forum = $this->getDataGenerator()->create_module('forum', (object) array(
2892              'course' => $course->id,
2893              'groupmode' => SEPARATEGROUPS,
2894          ));
2895  
2896          $coursemodule = get_coursemodule_from_instance('forum', $forum->id);
2897          $now = time();
2898          $discussions = array();
2899          $discussiongenerator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
2900  
2901          $record = new stdClass();
2902          $record->course = $course->id;
2903          $record->userid = $user->id;
2904          $record->forum = $forum->id;
2905          $record->pinned = FORUM_DISCUSSION_PINNED;
2906          $record->timemodified = $now;
2907          $record->timestart = $now + 10;
2908  
2909          $discussions[] = $discussiongenerator->create_discussion($record);
2910  
2911          $record->pinned = FORUM_DISCUSSION_UNPINNED;
2912  
2913          $discussions[] = $discussiongenerator->create_discussion($record);
2914  
2915          $record->timestart = $now;
2916  
2917          $discussions[] = $discussiongenerator->create_discussion($record);
2918  
2919          $record->pinned = FORUM_DISCUSSION_PINNED;
2920  
2921          $discussions[] = $discussiongenerator->create_discussion($record);
2922  
2923          // Expected order of discussions:
2924          // D2, d1, d3, d0.
2925          $this->setUser($user->id);
2926  
2927          // CHECK 1.
2928          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[2], $forum);
2929          // Null check.
2930          $this->assertEmpty($neighbours['prev']);
2931          // D1 check.
2932          $this->assertEquals($discussions[1]->id, $neighbours['next']->id);
2933  
2934          // CHECK 2.
2935          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[1], $forum);
2936          // D2 check.
2937          $this->assertEquals($discussions[2]->id, $neighbours['prev']->id);
2938          // D3 check.
2939          $this->assertEquals($discussions[3]->id, $neighbours['next']->id);
2940  
2941          // CHECK 3.
2942          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[3], $forum);
2943          // D1 check.
2944          $this->assertEquals($discussions[1]->id, $neighbours['prev']->id);
2945          // D0 check.
2946          $this->assertEquals($discussions[0]->id, $neighbours['next']->id);
2947  
2948          // CHECK 4.
2949          $neighbours = forum_get_discussion_neighbours($coursemodule, $discussions[0], $forum);
2950          // D3 check.
2951          $this->assertEquals($discussions[3]->id, $neighbours['prev']->id);
2952          // Null check.
2953          $this->assertEmpty($neighbours['next']);
2954      }
2955  
2956      /**
2957       * @dataProvider forum_get_unmailed_posts_provider
2958       */
2959      public function test_forum_get_unmailed_posts($discussiondata, $enabletimedposts, $expectedcount, $expectedreplycount) {
2960          global $CFG, $DB;
2961  
2962          $this->resetAfterTest();
2963  
2964          // Configure timed posts.
2965          $CFG->forum_enabletimedposts = $enabletimedposts;
2966  
2967          $course = $this->getDataGenerator()->create_course();
2968          $forum = $this->getDataGenerator()->create_module('forum', ['course' => $course->id]);
2969          $user = $this->getDataGenerator()->create_user();
2970          $forumgen = $this->getDataGenerator()->get_plugin_generator('mod_forum');
2971  
2972          // Keep track of the start time of the test. Do not use time() after this point to prevent random failures.
2973          $time = time();
2974  
2975          $record = new stdClass();
2976          $record->course = $course->id;
2977          $record->userid = $user->id;
2978          $record->forum = $forum->id;
2979          if (isset($discussiondata['timecreated'])) {
2980              $record->timemodified = $time + $discussiondata['timecreated'];
2981          }
2982          if (isset($discussiondata['timestart'])) {
2983              $record->timestart = $time + $discussiondata['timestart'];
2984          }
2985          if (isset($discussiondata['timeend'])) {
2986              $record->timeend = $time + $discussiondata['timeend'];
2987          }
2988          if (isset($discussiondata['mailed'])) {
2989              $record->mailed = $discussiondata['mailed'];
2990          }
2991  
2992          $discussion = $forumgen->create_discussion($record);
2993  
2994          // Fetch the unmailed posts.
2995          $timenow   = $time;
2996          $endtime   = $timenow - $CFG->maxeditingtime;
2997          $starttime = $endtime - 2 * DAYSECS;
2998  
2999          $unmailed = forum_get_unmailed_posts($starttime, $endtime, $timenow);
3000          $this->assertCount($expectedcount, $unmailed);
3001  
3002          // Add a reply just outside the maxeditingtime.
3003          $replyto = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
3004          $reply = new stdClass();
3005          $reply->userid = $user->id;
3006          $reply->discussion = $discussion->id;
3007          $reply->parent = $replyto->id;
3008          $reply->created = max($replyto->created, $endtime - 1);
3009          $forumgen->create_post($reply);
3010  
3011          $unmailed = forum_get_unmailed_posts($starttime, $endtime, $timenow);
3012          $this->assertCount($expectedreplycount, $unmailed);
3013      }
3014  
3015      /**
3016       * Test for forum_is_author_hidden.
3017       */
3018      public function test_forum_is_author_hidden() {
3019          // First post, different forum type.
3020          $post = (object) ['parent' => 0];
3021          $forum = (object) ['type' => 'standard'];
3022          $this->assertFalse(forum_is_author_hidden($post, $forum));
3023  
3024          // Child post, different forum type.
3025          $post->parent = 1;
3026          $this->assertFalse(forum_is_author_hidden($post, $forum));
3027  
3028          // First post, single simple discussion forum type.
3029          $post->parent = 0;
3030          $forum->type = 'single';
3031          $this->assertTrue(forum_is_author_hidden($post, $forum));
3032  
3033          // Child post, single simple discussion forum type.
3034          $post->parent = 1;
3035          $this->assertFalse(forum_is_author_hidden($post, $forum));
3036  
3037          // Incorrect parameters: $post.
3038          $this->expectException('coding_exception');
3039          $this->expectExceptionMessage('$post->parent must be set.');
3040          unset($post->parent);
3041          forum_is_author_hidden($post, $forum);
3042  
3043          // Incorrect parameters: $forum.
3044          $this->expectException('coding_exception');
3045          $this->expectExceptionMessage('$forum->type must be set.');
3046          unset($forum->type);
3047          forum_is_author_hidden($post, $forum);
3048      }
3049  
3050      public function forum_get_unmailed_posts_provider() {
3051          return [
3052              'Untimed discussion; Single post; maxeditingtime not expired' => [
3053                  'discussion'        => [
3054                  ],
3055                  'timedposts'        => false,
3056                  'postcount'         => 0,
3057                  'replycount'        => 0,
3058              ],
3059              'Untimed discussion; Single post; maxeditingtime expired' => [
3060                  'discussion'        => [
3061                      'timecreated'   => - DAYSECS,
3062                  ],
3063                  'timedposts'        => false,
3064                  'postcount'         => 1,
3065                  'replycount'        => 2,
3066              ],
3067              'Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime not expired' => [
3068                  'discussion'        => [
3069                      'timecreated'   => - WEEKSECS,
3070                      'timestart'     => 0,
3071                  ],
3072                  'timedposts'        => true,
3073                  'postcount'         => 0,
3074                  'replycount'        => 0,
3075              ],
3076              'Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired' => [
3077                  'discussion'        => [
3078                      'timecreated'   => - WEEKSECS,
3079                      'timestart'     => - DAYSECS,
3080                  ],
3081                  'timedposts'        => true,
3082                  'postcount'         => 1,
3083                  'replycount'        => 2,
3084              ],
3085              'Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired; timeend not reached' => [
3086                  'discussion'        => [
3087                      'timecreated'   => - WEEKSECS,
3088                      'timestart'     => - DAYSECS,
3089                      'timeend'       => + DAYSECS
3090                  ],
3091                  'timedposts'        => true,
3092                  'postcount'         => 1,
3093                  'replycount'        => 2,
3094              ],
3095              'Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired; timeend passed' => [
3096                  'discussion'        => [
3097                      'timecreated'   => - WEEKSECS,
3098                      'timestart'     => - DAYSECS,
3099                      'timeend'       => - HOURSECS,
3100                  ],
3101                  'timedposts'        => true,
3102                  'postcount'         => 0,
3103                  'replycount'        => 0,
3104              ],
3105              'Timed discussion; Single post; Posted 1 week ago; timeend not reached' => [
3106                  'discussion'        => [
3107                      'timecreated'   => - WEEKSECS,
3108                      'timeend'       => + DAYSECS
3109                  ],
3110                  'timedposts'        => true,
3111                  'postcount'         => 0,
3112                  'replycount'        => 1,
3113              ],
3114              'Timed discussion; Single post; Posted 1 week ago; timeend passed' => [
3115                  'discussion'        => [
3116                      'timecreated'   => - WEEKSECS,
3117                      'timeend'       => - DAYSECS,
3118                  ],
3119                  'timedposts'        => true,
3120                  'postcount'         => 0,
3121                  'replycount'        => 0,
3122              ],
3123  
3124              'Previously mailed; Untimed discussion; Single post; maxeditingtime not expired' => [
3125                  'discussion'        => [
3126                      'mailed'        => 1,
3127                  ],
3128                  'timedposts'        => false,
3129                  'postcount'         => 0,
3130                  'replycount'        => 0,
3131              ],
3132  
3133              'Previously mailed; Untimed discussion; Single post; maxeditingtime expired' => [
3134                  'discussion'        => [
3135                      'timecreated'   => - DAYSECS,
3136                      'mailed'        => 1,
3137                  ],
3138                  'timedposts'        => false,
3139                  'postcount'         => 0,
3140                  'replycount'        => 1,
3141              ],
3142              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime not expired' => [
3143                  'discussion'        => [
3144                      'timecreated'   => - WEEKSECS,
3145                      'timestart'     => 0,
3146                      'mailed'        => 1,
3147                  ],
3148                  'timedposts'        => true,
3149                  'postcount'         => 0,
3150                  'replycount'        => 0,
3151              ],
3152              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired' => [
3153                  'discussion'        => [
3154                      'timecreated'   => - WEEKSECS,
3155                      'timestart'     => - DAYSECS,
3156                      'mailed'        => 1,
3157                  ],
3158                  'timedposts'        => true,
3159                  'postcount'         => 0,
3160                  'replycount'        => 1,
3161              ],
3162              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired; timeend not reached' => [
3163                  'discussion'        => [
3164                      'timecreated'   => - WEEKSECS,
3165                      'timestart'     => - DAYSECS,
3166                      'timeend'       => + DAYSECS,
3167                      'mailed'        => 1,
3168                  ],
3169                  'timedposts'        => true,
3170                  'postcount'         => 0,
3171                  'replycount'        => 1,
3172              ],
3173              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timestart maxeditingtime expired; timeend passed' => [
3174                  'discussion'        => [
3175                      'timecreated'   => - WEEKSECS,
3176                      'timestart'     => - DAYSECS,
3177                      'timeend'       => - HOURSECS,
3178                      'mailed'        => 1,
3179                  ],
3180                  'timedposts'        => true,
3181                  'postcount'         => 0,
3182                  'replycount'        => 0,
3183              ],
3184              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timeend not reached' => [
3185                  'discussion'        => [
3186                      'timecreated'   => - WEEKSECS,
3187                      'timeend'       => + DAYSECS,
3188                      'mailed'        => 1,
3189                  ],
3190                  'timedposts'        => true,
3191                  'postcount'         => 0,
3192                  'replycount'        => 1,
3193              ],
3194              'Previously mailed; Timed discussion; Single post; Posted 1 week ago; timeend passed' => [
3195                  'discussion'        => [
3196                      'timecreated'   => - WEEKSECS,
3197                      'timeend'       => - DAYSECS,
3198                      'mailed'        => 1,
3199                  ],
3200                  'timedposts'        => true,
3201                  'postcount'         => 0,
3202                  'replycount'        => 0,
3203              ],
3204          ];
3205      }
3206  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1