Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 39 and 311]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace core;
  18  
  19  use filter_manager;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  global $CFG;
  24  require_once($CFG->libdir . '/filterlib.php');
  25  
  26  /**
  27   * Test filters.
  28   *
  29   * Tests for the parts of ../filterlib.php that involve loading the configuration
  30   * from, and saving the configuration to, the database.
  31   *
  32   * @package   core
  33   * @category  test
  34   * @copyright 2009 Tim Hunt
  35   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class filterlib_test extends \advanced_testcase {
  38  
  39      private function assert_only_one_filter_globally($filter, $state) {
  40          global $DB;
  41          $recs = $DB->get_records('filter_active');
  42          $this->assertCount(1, $recs);
  43          $rec = reset($recs);
  44          unset($rec->id);
  45          $expectedrec = new \stdClass();
  46          $expectedrec->filter = $filter;
  47          $expectedrec->contextid = \context_system::instance()->id;
  48          $expectedrec->active = $state;
  49          $expectedrec->sortorder = 1;
  50          $this->assertEquals($expectedrec, $rec);
  51      }
  52  
  53      private function assert_global_sort_order($filters) {
  54          global $DB;
  55  
  56          $sortedfilters = $DB->get_records_menu('filter_active',
  57              array('contextid' => \context_system::instance()->id), 'sortorder', 'sortorder,filter');
  58          $testarray = array();
  59          $index = 1;
  60          foreach ($filters as $filter) {
  61              $testarray[$index++] = $filter;
  62          }
  63          $this->assertEquals($testarray, $sortedfilters);
  64      }
  65  
  66      public function test_set_filter_globally_on() {
  67          $this->resetAfterTest();
  68          $this->remove_all_filters_from_config(); // Remove all filters.
  69          // Setup fixture.
  70          // Exercise SUT.
  71          filter_set_global_state('name', TEXTFILTER_ON);
  72          // Validate.
  73          $this->assert_only_one_filter_globally('name', TEXTFILTER_ON);
  74      }
  75  
  76      public function test_set_filter_globally_off() {
  77          $this->resetAfterTest();
  78          $this->remove_all_filters_from_config(); // Remove all filters.
  79          // Setup fixture.
  80          // Exercise SUT.
  81          filter_set_global_state('name', TEXTFILTER_OFF);
  82          // Validate.
  83          $this->assert_only_one_filter_globally('name', TEXTFILTER_OFF);
  84      }
  85  
  86      public function test_set_filter_globally_disabled() {
  87          $this->resetAfterTest();
  88          $this->remove_all_filters_from_config(); // Remove all filters.
  89          // Setup fixture.
  90          // Exercise SUT.
  91          filter_set_global_state('name', TEXTFILTER_DISABLED);
  92          // Validate.
  93          $this->assert_only_one_filter_globally('name', TEXTFILTER_DISABLED);
  94      }
  95  
  96      public function test_global_config_exception_on_invalid_state() {
  97          $this->resetAfterTest();
  98          $this->expectException(\coding_exception::class);
  99          filter_set_global_state('name', 0);
 100      }
 101  
 102      public function test_auto_sort_order() {
 103          $this->resetAfterTest();
 104          $this->remove_all_filters_from_config(); // Remove all filters.
 105          // Setup fixture.
 106          // Exercise SUT.
 107          filter_set_global_state('one', TEXTFILTER_DISABLED);
 108          filter_set_global_state('two', TEXTFILTER_DISABLED);
 109          // Validate.
 110          $this->assert_global_sort_order(array('one', 'two'));
 111      }
 112  
 113      public function test_auto_sort_order_enabled() {
 114          $this->resetAfterTest();
 115          $this->remove_all_filters_from_config(); // Remove all filters.
 116          // Setup fixture.
 117          // Exercise SUT.
 118          filter_set_global_state('one', TEXTFILTER_ON);
 119          filter_set_global_state('two', TEXTFILTER_OFF);
 120          // Validate.
 121          $this->assert_global_sort_order(array('one', 'two'));
 122      }
 123  
 124      public function test_update_existing_dont_duplicate() {
 125          $this->resetAfterTest();
 126          $this->remove_all_filters_from_config(); // Remove all filters.
 127          // Setup fixture.
 128          // Exercise SUT.
 129          filter_set_global_state('name', TEXTFILTER_ON);
 130          filter_set_global_state('name', TEXTFILTER_OFF);
 131          // Validate.
 132          $this->assert_only_one_filter_globally('name', TEXTFILTER_OFF);
 133      }
 134  
 135      public function test_update_reorder_down() {
 136          global $DB;
 137  
 138          $this->resetAfterTest();
 139          $this->remove_all_filters_from_config(); // Remove all filters.
 140          // Setup fixture.
 141          filter_set_global_state('one', TEXTFILTER_ON);
 142          filter_set_global_state('two', TEXTFILTER_ON);
 143          filter_set_global_state('three', TEXTFILTER_ON);
 144          // Exercise SUT.
 145          filter_set_global_state('two', TEXTFILTER_ON, -1);
 146          // Validate.
 147          $this->assert_global_sort_order(array('two', 'one', 'three'));
 148  
 149          // Check this was logged in config log.
 150          $logs = $DB->get_records('config_log', null, 'id DESC', '*', 0, 1);
 151          $log = reset($logs);
 152          $this->assertEquals('core_filter', $log->plugin);
 153          $this->assertEquals('order', $log->name);
 154          $this->assertEquals('two, one, three', $log->value);
 155          $this->assertEquals('one, two, three', $log->oldvalue);
 156      }
 157  
 158      public function test_update_reorder_up() {
 159          global $DB;
 160  
 161          $this->resetAfterTest();
 162          $this->remove_all_filters_from_config(); // Remove all filters.
 163          // Setup fixture.
 164          filter_set_global_state('one', TEXTFILTER_ON);
 165          filter_set_global_state('two', TEXTFILTER_ON);
 166          filter_set_global_state('three', TEXTFILTER_ON);
 167          filter_set_global_state('four', TEXTFILTER_ON);
 168          // Exercise SUT.
 169          filter_set_global_state('two', TEXTFILTER_ON, 1);
 170          // Validate.
 171          $this->assert_global_sort_order(array('one', 'three', 'two', 'four'));
 172  
 173          // Check this was logged in config log.
 174          $logs = $DB->get_records('config_log', null, 'id DESC', '*', 0, 1);
 175          $log = reset($logs);
 176          $this->assertEquals('core_filter', $log->plugin);
 177          $this->assertEquals('order', $log->name);
 178          $this->assertEquals('one, three, two, four', $log->value);
 179          $this->assertEquals('one, two, three, four', $log->oldvalue);
 180      }
 181  
 182      public function test_auto_sort_order_change_to_enabled() {
 183          $this->resetAfterTest();
 184          $this->remove_all_filters_from_config(); // Remove all filters.
 185          // Setup fixture.
 186          filter_set_global_state('one', TEXTFILTER_ON);
 187          filter_set_global_state('two', TEXTFILTER_DISABLED);
 188          filter_set_global_state('three', TEXTFILTER_DISABLED);
 189          // Exercise SUT.
 190          filter_set_global_state('three', TEXTFILTER_ON);
 191          // Validate.
 192          $this->assert_global_sort_order(array('one', 'three', 'two'));
 193      }
 194  
 195      public function test_auto_sort_order_change_to_disabled() {
 196          $this->resetAfterTest();
 197          $this->remove_all_filters_from_config(); // Remove all filters.
 198          // Setup fixture.
 199          filter_set_global_state('one', TEXTFILTER_ON);
 200          filter_set_global_state('two', TEXTFILTER_ON);
 201          filter_set_global_state('three', TEXTFILTER_DISABLED);
 202          // Exercise SUT.
 203          filter_set_global_state('one', TEXTFILTER_DISABLED);
 204          // Validate.
 205          $this->assert_global_sort_order(array('two', 'one', 'three'));
 206      }
 207  
 208      public function test_filter_get_global_states() {
 209          $this->resetAfterTest();
 210          $this->remove_all_filters_from_config(); // Remove all filters.
 211          // Setup fixture.
 212          filter_set_global_state('one', TEXTFILTER_ON);
 213          filter_set_global_state('two', TEXTFILTER_OFF);
 214          filter_set_global_state('three', TEXTFILTER_DISABLED);
 215          // Exercise SUT.
 216          $filters = filter_get_global_states();
 217          // Validate.
 218          $this->assertEquals(array(
 219              'one' => (object) array('filter' => 'one', 'active' => TEXTFILTER_ON, 'sortorder' => 1),
 220              'two' => (object) array('filter' => 'two', 'active' => TEXTFILTER_OFF, 'sortorder' => 2),
 221              'three' => (object) array('filter' => 'three', 'active' => TEXTFILTER_DISABLED, 'sortorder' => 3)
 222          ), $filters);
 223      }
 224  
 225      private function assert_only_one_local_setting($filter, $contextid, $state) {
 226          global $DB;
 227          $recs = $DB->get_records('filter_active');
 228          $this->assertEquals(1, count($recs), 'More than one record returned %s.');
 229          $rec = reset($recs);
 230          unset($rec->id);
 231          unset($rec->sortorder);
 232          $expectedrec = new \stdClass();
 233          $expectedrec->filter = $filter;
 234          $expectedrec->contextid = $contextid;
 235          $expectedrec->active = $state;
 236          $this->assertEquals($expectedrec, $rec);
 237      }
 238  
 239      private function assert_no_local_setting() {
 240          global $DB;
 241          $this->assertEquals(0, $DB->count_records('filter_active'));
 242      }
 243  
 244      public function test_local_on() {
 245          $this->resetAfterTest();
 246          $this->remove_all_filters_from_config(); // Remove all filters.
 247          // Exercise SUT.
 248          filter_set_local_state('name', 123, TEXTFILTER_ON);
 249          // Validate.
 250          $this->assert_only_one_local_setting('name', 123, TEXTFILTER_ON);
 251      }
 252  
 253      public function test_local_off() {
 254          $this->resetAfterTest();
 255          $this->remove_all_filters_from_config(); // Remove all filters.
 256          // Exercise SUT.
 257          filter_set_local_state('name', 123, TEXTFILTER_OFF);
 258          // Validate.
 259          $this->assert_only_one_local_setting('name', 123, TEXTFILTER_OFF);
 260      }
 261  
 262      public function test_local_inherit() {
 263          $this->resetAfterTest();
 264          $this->remove_all_filters_from_config(); // Remove all filters.
 265          // Exercise SUT.
 266          filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
 267          // Validate.
 268          $this->assert_no_local_setting();
 269      }
 270  
 271      public function test_local_invalid_state_throws_exception() {
 272          $this->resetAfterTest();
 273          // Exercise SUT.
 274          $this->expectException(\coding_exception::class);
 275          filter_set_local_state('name', 123, -9999);
 276      }
 277  
 278      public function test_throws_exception_when_setting_global() {
 279          $this->resetAfterTest();
 280          // Exercise SUT.
 281          $this->expectException(\coding_exception::class);
 282          filter_set_local_state('name', \context_system::instance()->id, TEXTFILTER_INHERIT);
 283      }
 284  
 285      public function test_local_inherit_deletes_existing() {
 286          $this->resetAfterTest();
 287          $this->remove_all_filters_from_config(); // Remove all filters.
 288          // Setup fixture.
 289          filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
 290          // Exercise SUT.
 291          filter_set_local_state('name', 123, TEXTFILTER_INHERIT);
 292          // Validate.
 293          $this->assert_no_local_setting();
 294      }
 295  
 296      private function assert_only_one_config($filter, $context, $name, $value) {
 297          global $DB;
 298          $recs = $DB->get_records('filter_config');
 299          $this->assertEquals(1, count($recs), 'More than one record returned %s.');
 300          $rec = reset($recs);
 301          unset($rec->id);
 302          $expectedrec = new \stdClass();
 303          $expectedrec->filter = $filter;
 304          $expectedrec->contextid = $context;
 305          $expectedrec->name = $name;
 306          $expectedrec->value = $value;
 307          $this->assertEquals($expectedrec, $rec);
 308      }
 309  
 310      public function test_set_new_config() {
 311          $this->resetAfterTest();
 312          $this->remove_all_filters_from_config(); // Remove all filters.
 313          // Exercise SUT.
 314          filter_set_local_config('name', 123, 'settingname', 'An arbitrary value');
 315          // Validate.
 316          $this->assert_only_one_config('name', 123, 'settingname', 'An arbitrary value');
 317      }
 318  
 319      public function test_update_existing_config() {
 320          $this->resetAfterTest();
 321          $this->remove_all_filters_from_config(); // Remove all filters.
 322          // Setup fixture.
 323          filter_set_local_config('name', 123, 'settingname', 'An arbitrary value');
 324          // Exercise SUT.
 325          filter_set_local_config('name', 123, 'settingname', 'A changed value');
 326          // Validate.
 327          $this->assert_only_one_config('name', 123, 'settingname', 'A changed value');
 328      }
 329  
 330      public function test_filter_get_local_config() {
 331          $this->resetAfterTest();
 332          // Setup fixture.
 333          filter_set_local_config('name', 123, 'setting1', 'An arbitrary value');
 334          filter_set_local_config('name', 123, 'setting2', 'Another arbitrary value');
 335          filter_set_local_config('name', 122, 'settingname', 'Value from another context');
 336          filter_set_local_config('other', 123, 'settingname', 'Someone else\'s value');
 337          // Exercise SUT.
 338          $config = filter_get_local_config('name', 123);
 339          // Validate.
 340          $this->assertEquals(array('setting1' => 'An arbitrary value', 'setting2' => 'Another arbitrary value'), $config);
 341      }
 342  
 343      protected function setup_available_in_context_tests() {
 344          $course = $this->getDataGenerator()->create_course(array('category' => 1));
 345  
 346          $childcontext = \context_coursecat::instance(1);
 347          $childcontext2 = \context_course::instance($course->id);
 348          $syscontext = \context_system::instance();
 349  
 350          return [
 351              'syscontext' => $syscontext,
 352              'childcontext' => $childcontext,
 353              'childcontext2' => $childcontext2
 354          ];
 355      }
 356  
 357      protected function remove_all_filters_from_config() {
 358          global $DB;
 359          $DB->delete_records('filter_active', array());
 360          $DB->delete_records('filter_config', array());
 361      }
 362  
 363      private function assert_filter_list($expectedfilters, $filters) {
 364          $this->assertEqualsCanonicalizing($expectedfilters, array_keys($filters));
 365      }
 366  
 367      public function test_globally_on_is_returned() {
 368          $this->resetAfterTest();
 369          $this->remove_all_filters_from_config(); // Remove all filters.
 370          [
 371              'syscontext' => $syscontext
 372          ] = $this->setup_available_in_context_tests();
 373          // Setup fixture.
 374          filter_set_global_state('name', TEXTFILTER_ON);
 375          // Exercise SUT.
 376          $filters = filter_get_active_in_context($syscontext);
 377          // Validate.
 378          $this->assert_filter_list(array('name'), $filters);
 379          // Check no config returned correctly.
 380          $this->assertEquals(array(), $filters['name']);
 381      }
 382  
 383      public function test_globally_off_not_returned() {
 384          $this->resetAfterTest();
 385          $this->remove_all_filters_from_config(); // Remove all filters.
 386          [
 387              'childcontext2' => $childcontext2
 388          ] = $this->setup_available_in_context_tests();
 389          // Setup fixture.
 390          filter_set_global_state('name', TEXTFILTER_OFF);
 391          // Exercise SUT.
 392          $filters = filter_get_active_in_context($childcontext2);
 393          // Validate.
 394          $this->assert_filter_list(array(), $filters);
 395      }
 396  
 397      public function test_globally_off_overridden() {
 398          $this->resetAfterTest();
 399          $this->remove_all_filters_from_config(); // Remove all filters.
 400          [
 401              'childcontext' => $childcontext,
 402              'childcontext2' => $childcontext2
 403          ] = $this->setup_available_in_context_tests();
 404          // Setup fixture.
 405          filter_set_global_state('name', TEXTFILTER_OFF);
 406          filter_set_local_state('name', $childcontext->id, TEXTFILTER_ON);
 407          // Exercise SUT.
 408          $filters = filter_get_active_in_context($childcontext2);
 409          // Validate.
 410          $this->assert_filter_list(array('name'), $filters);
 411      }
 412  
 413      public function test_globally_on_overridden() {
 414          $this->resetAfterTest();
 415          $this->remove_all_filters_from_config(); // Remove all filters.
 416          [
 417              'childcontext' => $childcontext,
 418              'childcontext2' => $childcontext2
 419          ] = $this->setup_available_in_context_tests();
 420          // Setup fixture.
 421          filter_set_global_state('name', TEXTFILTER_ON);
 422          filter_set_local_state('name', $childcontext->id, TEXTFILTER_OFF);
 423          // Exercise SUT.
 424          $filters = filter_get_active_in_context($childcontext2);
 425          // Validate.
 426          $this->assert_filter_list(array(), $filters);
 427      }
 428  
 429      public function test_globally_disabled_not_overridden() {
 430          $this->resetAfterTest();
 431          $this->remove_all_filters_from_config(); // Remove all filters.
 432          [
 433              'syscontext' => $syscontext,
 434              'childcontext' => $childcontext
 435          ] = $this->setup_available_in_context_tests();
 436          // Setup fixture.
 437          filter_set_global_state('name', TEXTFILTER_DISABLED);
 438          filter_set_local_state('name', $childcontext->id, TEXTFILTER_ON);
 439          // Exercise SUT.
 440          $filters = filter_get_active_in_context($syscontext);
 441          // Validate.
 442          $this->assert_filter_list(array(), $filters);
 443      }
 444  
 445      public function test_single_config_returned() {
 446          $this->resetAfterTest();
 447          [
 448              'childcontext' => $childcontext
 449          ] = $this->setup_available_in_context_tests();
 450          // Setup fixture.
 451          filter_set_global_state('name', TEXTFILTER_ON);
 452          filter_set_local_config('name', $childcontext->id, 'settingname', 'A value');
 453          // Exercise SUT.
 454          $filters = filter_get_active_in_context($childcontext);
 455          // Validate.
 456          $this->assertEquals(array('settingname' => 'A value'), $filters['name']);
 457      }
 458  
 459      public function test_multi_config_returned() {
 460          $this->resetAfterTest();
 461          [
 462              'childcontext' => $childcontext
 463          ] = $this->setup_available_in_context_tests();
 464          // Setup fixture.
 465          filter_set_global_state('name', TEXTFILTER_ON);
 466          filter_set_local_config('name', $childcontext->id, 'settingname', 'A value');
 467          filter_set_local_config('name', $childcontext->id, 'anothersettingname', 'Another value');
 468          // Exercise SUT.
 469          $filters = filter_get_active_in_context($childcontext);
 470          // Validate.
 471          $this->assertEquals(array('settingname' => 'A value', 'anothersettingname' => 'Another value'), $filters['name']);
 472      }
 473  
 474      public function test_config_from_other_context_not_returned() {
 475          $this->resetAfterTest();
 476          [
 477              'childcontext' => $childcontext,
 478              'childcontext2' => $childcontext2
 479          ] = $this->setup_available_in_context_tests();
 480          // Setup fixture.
 481          filter_set_global_state('name', TEXTFILTER_ON);
 482          filter_set_local_config('name', $childcontext->id, 'settingname', 'A value');
 483          filter_set_local_config('name', $childcontext2->id, 'anothersettingname', 'Another value');
 484          // Exercise SUT.
 485          $filters = filter_get_active_in_context($childcontext2);
 486          // Validate.
 487          $this->assertEquals(array('anothersettingname' => 'Another value'), $filters['name']);
 488      }
 489  
 490      public function test_config_from_other_filter_not_returned() {
 491          $this->resetAfterTest();
 492          [
 493              'childcontext' => $childcontext
 494          ] = $this->setup_available_in_context_tests();
 495          // Setup fixture.
 496          filter_set_global_state('name', TEXTFILTER_ON);
 497          filter_set_local_config('name', $childcontext->id, 'settingname', 'A value');
 498          filter_set_local_config('other', $childcontext->id, 'anothersettingname', 'Another value');
 499          // Exercise SUT.
 500          $filters = filter_get_active_in_context($childcontext);
 501          // Validate.
 502          $this->assertEquals(array('settingname' => 'A value'), $filters['name']);
 503      }
 504  
 505      protected function assert_one_available_filter($filter, $localstate, $inheritedstate, $filters) {
 506          $this->assertEquals(1, count($filters), 'More than one record returned %s.');
 507          $rec = $filters[$filter];
 508          unset($rec->id);
 509          $expectedrec = new \stdClass();
 510          $expectedrec->filter = $filter;
 511          $expectedrec->localstate = $localstate;
 512          $expectedrec->inheritedstate = $inheritedstate;
 513          $this->assertEquals($expectedrec, $rec);
 514      }
 515  
 516      public function test_available_in_context_localoverride() {
 517          $this->resetAfterTest();
 518          $this->remove_all_filters_from_config(); // Remove all filters.
 519          [
 520              'childcontext' => $childcontext
 521          ] = $this->setup_available_in_context_tests();
 522          // Setup fixture.
 523          filter_set_global_state('name', TEXTFILTER_ON);
 524          filter_set_local_state('name', $childcontext->id, TEXTFILTER_OFF);
 525          // Exercise SUT.
 526          $filters = filter_get_available_in_context($childcontext);
 527          // Validate.
 528          $this->assert_one_available_filter('name', TEXTFILTER_OFF, TEXTFILTER_ON, $filters);
 529      }
 530  
 531      public function test_available_in_context_nolocaloverride() {
 532          $this->resetAfterTest();
 533          $this->remove_all_filters_from_config(); // Remove all filters.
 534          [
 535              'childcontext' => $childcontext,
 536              'childcontext2' => $childcontext2
 537          ] = $this->setup_available_in_context_tests();
 538          // Setup fixture.
 539          filter_set_global_state('name', TEXTFILTER_ON);
 540          filter_set_local_state('name', $childcontext->id, TEXTFILTER_OFF);
 541          // Exercise SUT.
 542          $filters = filter_get_available_in_context($childcontext2);
 543          // Validate.
 544          $this->assert_one_available_filter('name', TEXTFILTER_INHERIT, TEXTFILTER_OFF, $filters);
 545      }
 546  
 547      public function test_available_in_context_disabled_not_returned() {
 548          $this->resetAfterTest();
 549          $this->remove_all_filters_from_config(); // Remove all filters.
 550          [
 551              'childcontext' => $childcontext
 552          ] = $this->setup_available_in_context_tests();
 553          // Setup fixture.
 554          filter_set_global_state('name', TEXTFILTER_DISABLED);
 555          filter_set_local_state('name', $childcontext->id, TEXTFILTER_ON);
 556          // Exercise SUT.
 557          $filters = filter_get_available_in_context($childcontext);
 558          // Validate.
 559          $this->assertEquals(array(), $filters);
 560      }
 561  
 562      public function test_available_in_context_exception_with_syscontext() {
 563          $this->resetAfterTest();
 564          [
 565              'syscontext' => $syscontext
 566          ] = $this->setup_available_in_context_tests();
 567          // Exercise SUT.
 568          $this->expectException(\coding_exception::class);
 569          filter_get_available_in_context($syscontext);
 570      }
 571  
 572      protected function setup_preload_activities_test() {
 573          $syscontext = \context_system::instance();
 574          $catcontext = \context_coursecat::instance(1);
 575          $course = $this->getDataGenerator()->create_course(array('category' => 1));
 576          $coursecontext = \context_course::instance($course->id);
 577          $page1 = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
 578          $activity1context = \context_module::instance($page1->cmid);
 579          $page2 = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
 580          $activity2context = \context_module::instance($page2->cmid);
 581          return [
 582              'syscontext' => $syscontext,
 583              'catcontext' => $catcontext,
 584              'course' => $course,
 585              'coursecontext' => $coursecontext,
 586              'activity1context' => $activity1context,
 587              'activity2context' => $activity2context
 588           ];
 589      }
 590  
 591      private function assert_matches($modinfo, $activity1context, $activity2context) {
 592          global $FILTERLIB_PRIVATE, $DB;
 593  
 594          // Use preload cache...
 595          $FILTERLIB_PRIVATE = new \stdClass();
 596          filter_preload_activities($modinfo);
 597  
 598          // Get data and check no queries are made.
 599          $before = $DB->perf_get_reads();
 600          $plfilters1 = filter_get_active_in_context($activity1context);
 601          $plfilters2 = filter_get_active_in_context($activity2context);
 602          $after = $DB->perf_get_reads();
 603          $this->assertEquals($before, $after);
 604  
 605          // Repeat without cache and check it makes queries now.
 606          $FILTERLIB_PRIVATE = new \stdClass;
 607          $before = $DB->perf_get_reads();
 608          $filters1 = filter_get_active_in_context($activity1context);
 609          $filters2 = filter_get_active_in_context($activity2context);
 610          $after = $DB->perf_get_reads();
 611          $this->assertTrue($after > $before);
 612  
 613          // Check they match.
 614          $this->assertEquals($plfilters1, $filters1);
 615          $this->assertEquals($plfilters2, $filters2);
 616      }
 617  
 618      public function test_preload() {
 619          $this->resetAfterTest();
 620          [
 621              'catcontext' => $catcontext,
 622              'course' => $course,
 623              'coursecontext' => $coursecontext,
 624              'activity1context' => $activity1context,
 625              'activity2context' => $activity2context
 626           ] = $this->setup_preload_activities_test();
 627          // Get course and modinfo.
 628          $modinfo = new \course_modinfo($course, 2);
 629  
 630          // Note: All the tests in this function check that the result from the
 631          // preloaded cache is the same as the result from calling the standard
 632          // function without preloading.
 633  
 634          // Initially, check with no filters enabled.
 635          $this->assert_matches($modinfo, $activity1context, $activity2context);
 636  
 637          // Enable filter globally, check.
 638          filter_set_global_state('name', TEXTFILTER_ON);
 639          $this->assert_matches($modinfo, $activity1context, $activity2context);
 640  
 641          // Disable for activity 2.
 642          filter_set_local_state('name', $activity2context->id, TEXTFILTER_OFF);
 643          $this->assert_matches($modinfo, $activity1context, $activity2context);
 644  
 645          // Disable at category.
 646          filter_set_local_state('name', $catcontext->id, TEXTFILTER_OFF);
 647          $this->assert_matches($modinfo, $activity1context, $activity2context);
 648  
 649          // Enable for activity 1.
 650          filter_set_local_state('name', $activity1context->id, TEXTFILTER_ON);
 651          $this->assert_matches($modinfo, $activity1context, $activity2context);
 652  
 653          // Disable globally.
 654          filter_set_global_state('name', TEXTFILTER_DISABLED);
 655          $this->assert_matches($modinfo, $activity1context, $activity2context);
 656  
 657          // Add another 2 filters.
 658          filter_set_global_state('frog', TEXTFILTER_ON);
 659          filter_set_global_state('zombie', TEXTFILTER_ON);
 660          $this->assert_matches($modinfo, $activity1context, $activity2context);
 661  
 662          // Disable random one of these in each context.
 663          filter_set_local_state('zombie', $activity1context->id, TEXTFILTER_OFF);
 664          filter_set_local_state('frog', $activity2context->id, TEXTFILTER_OFF);
 665          $this->assert_matches($modinfo, $activity1context, $activity2context);
 666  
 667          // Now do some filter options.
 668          filter_set_local_config('name', $activity1context->id, 'a', 'x');
 669          filter_set_local_config('zombie', $activity1context->id, 'a', 'y');
 670          filter_set_local_config('frog', $activity1context->id, 'a', 'z');
 671          // These last two don't do anything as they are not at final level but I
 672          // thought it would be good to have that verified in test.
 673          filter_set_local_config('frog', $coursecontext->id, 'q', 'x');
 674          filter_set_local_config('frog', $catcontext->id, 'q', 'z');
 675          $this->assert_matches($modinfo, $activity1context, $activity2context);
 676      }
 677  
 678      public function test_filter_delete_all_for_filter() {
 679          global $DB;
 680          $this->resetAfterTest();
 681          $this->remove_all_filters_from_config(); // Remove all filters.
 682  
 683          // Setup fixture.
 684          filter_set_global_state('name', TEXTFILTER_ON);
 685          filter_set_global_state('other', TEXTFILTER_ON);
 686          filter_set_local_config('name', \context_system::instance()->id, 'settingname', 'A value');
 687          filter_set_local_config('other', \context_system::instance()->id, 'settingname', 'Other value');
 688          set_config('configname', 'A config value', 'filter_name');
 689          set_config('configname', 'Other config value', 'filter_other');
 690          // Exercise SUT.
 691          filter_delete_all_for_filter('name');
 692          // Validate.
 693          $this->assertEquals(1, $DB->count_records('filter_active'));
 694          $this->assertTrue($DB->record_exists('filter_active', array('filter' => 'other')));
 695          $this->assertEquals(1, $DB->count_records('filter_config'));
 696          $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'other')));
 697          $expectedconfig = new \stdClass;
 698          $expectedconfig->configname = 'Other config value';
 699          $this->assertEquals($expectedconfig, get_config('filter_other'));
 700          $this->assertEquals(get_config('filter_name'), new \stdClass());
 701      }
 702  
 703      public function test_filter_delete_all_for_context() {
 704          global $DB;
 705          $this->resetAfterTest();
 706          $this->remove_all_filters_from_config(); // Remove all filters.
 707  
 708          // Setup fixture.
 709          filter_set_global_state('name', TEXTFILTER_ON);
 710          filter_set_local_state('name', 123, TEXTFILTER_OFF);
 711          filter_set_local_config('name', 123, 'settingname', 'A value');
 712          filter_set_local_config('other', 123, 'settingname', 'Other value');
 713          filter_set_local_config('other', 122, 'settingname', 'Other value');
 714          // Exercise SUT.
 715          filter_delete_all_for_context(123);
 716          // Validate.
 717          $this->assertEquals(1, $DB->count_records('filter_active'));
 718          $this->assertTrue($DB->record_exists('filter_active', array('contextid' => \context_system::instance()->id)));
 719          $this->assertEquals(1, $DB->count_records('filter_config'));
 720          $this->assertTrue($DB->record_exists('filter_config', array('filter' => 'other')));
 721      }
 722  
 723      public function test_set() {
 724          global $CFG;
 725          $this->resetAfterTest();
 726  
 727          $this->assertFileExists("$CFG->dirroot/filter/emailprotect"); // Any standard filter.
 728          $this->assertFileExists("$CFG->dirroot/filter/tidy");         // Any standard filter.
 729          $this->assertFileDoesNotExist("$CFG->dirroot/filter/grgrggr");   // Any non-existent filter.
 730  
 731          // Setup fixture.
 732          set_config('filterall', 0);
 733          set_config('stringfilters', '');
 734          // Exercise SUT.
 735          filter_set_applies_to_strings('tidy', true);
 736          // Validate.
 737          $this->assertEquals('tidy', $CFG->stringfilters);
 738          $this->assertEquals(1, $CFG->filterall);
 739  
 740          filter_set_applies_to_strings('grgrggr', true);
 741          $this->assertEquals('tidy', $CFG->stringfilters);
 742          $this->assertEquals(1, $CFG->filterall);
 743  
 744          filter_set_applies_to_strings('emailprotect', true);
 745          $this->assertEquals('tidy,emailprotect', $CFG->stringfilters);
 746          $this->assertEquals(1, $CFG->filterall);
 747      }
 748  
 749      public function test_unset_to_empty() {
 750          global $CFG;
 751          $this->resetAfterTest();
 752  
 753          $this->assertFileExists("$CFG->dirroot/filter/tidy"); // Any standard filter.
 754  
 755          // Setup fixture.
 756          set_config('filterall', 1);
 757          set_config('stringfilters', 'tidy');
 758          // Exercise SUT.
 759          filter_set_applies_to_strings('tidy', false);
 760          // Validate.
 761          $this->assertEquals('', $CFG->stringfilters);
 762          $this->assertEquals('', $CFG->filterall);
 763      }
 764  
 765      public function test_unset_multi() {
 766          global $CFG;
 767          $this->resetAfterTest();
 768  
 769          $this->assertFileExists("$CFG->dirroot/filter/emailprotect"); // Any standard filter.
 770          $this->assertFileExists("$CFG->dirroot/filter/tidy");         // Any standard filter.
 771          $this->assertFileExists("$CFG->dirroot/filter/multilang");    // Any standard filter.
 772  
 773          // Setup fixture.
 774          set_config('filterall', 1);
 775          set_config('stringfilters', 'emailprotect,tidy,multilang');
 776          // Exercise SUT.
 777          filter_set_applies_to_strings('tidy', false);
 778          // Validate.
 779          $this->assertEquals('emailprotect,multilang', $CFG->stringfilters);
 780          $this->assertEquals(1, $CFG->filterall);
 781      }
 782  
 783      public function test_filter_manager_instance() {
 784          $this->resetAfterTest();
 785  
 786          set_config('perfdebug', 7);
 787          filter_manager::reset_caches();
 788          $filterman = filter_manager::instance();
 789          $this->assertInstanceOf('filter_manager', $filterman);
 790          $this->assertNotInstanceOf('performance_measuring_filter_manager', $filterman);
 791  
 792          set_config('perfdebug', 15);
 793          filter_manager::reset_caches();
 794          $filterman = filter_manager::instance();
 795          $this->assertInstanceOf('filter_manager', $filterman);
 796          $this->assertInstanceOf('performance_measuring_filter_manager', $filterman);
 797      }
 798  
 799      public function test_filter_get_active_state_contextid_parameter() {
 800          $this->resetAfterTest();
 801  
 802          filter_set_global_state('glossary', TEXTFILTER_ON);
 803          // Using system context by default.
 804          $active = filter_get_active_state('glossary');
 805          $this->assertEquals($active, TEXTFILTER_ON);
 806  
 807          $systemcontext = \context_system::instance();
 808          // Passing $systemcontext object.
 809          $active = filter_get_active_state('glossary', $systemcontext);
 810          $this->assertEquals($active, TEXTFILTER_ON);
 811  
 812          // Passing $systemcontext id.
 813          $active = filter_get_active_state('glossary', $systemcontext->id);
 814          $this->assertEquals($active, TEXTFILTER_ON);
 815  
 816          // Not system context.
 817          filter_set_local_state('glossary', '123', TEXTFILTER_ON);
 818          $active = filter_get_active_state('glossary', '123');
 819          $this->assertEquals($active, TEXTFILTER_ON);
 820      }
 821  
 822      public function test_filter_get_active_state_filtername_parameter() {
 823          $this->resetAfterTest();
 824  
 825          filter_set_global_state('glossary', TEXTFILTER_ON);
 826          // Using full filtername.
 827          $active = filter_get_active_state('filter/glossary');
 828          $this->assertEquals($active, TEXTFILTER_ON);
 829  
 830          // Wrong filtername.
 831          $this->expectException('coding_exception');
 832          $active = filter_get_active_state('mod/glossary');
 833      }
 834  
 835      public function test_filter_get_active_state_after_change() {
 836          $this->resetAfterTest();
 837  
 838          filter_set_global_state('glossary', TEXTFILTER_ON);
 839          $systemcontextid = \context_system::instance()->id;
 840          $active = filter_get_active_state('glossary', $systemcontextid);
 841          $this->assertEquals($active, TEXTFILTER_ON);
 842  
 843          filter_set_global_state('glossary', TEXTFILTER_OFF);
 844          $systemcontextid = \context_system::instance()->id;
 845          $active = filter_get_active_state('glossary', $systemcontextid);
 846          $this->assertEquals($active, TEXTFILTER_OFF);
 847  
 848          filter_set_global_state('glossary', TEXTFILTER_DISABLED);
 849          $systemcontextid = \context_system::instance()->id;
 850          $active = filter_get_active_state('glossary', $systemcontextid);
 851          $this->assertEquals($active, TEXTFILTER_DISABLED);
 852      }
 853  
 854      public function test_filter_get_globally_enabled_default() {
 855          $this->resetAfterTest();
 856          $enabledfilters = filter_get_globally_enabled();
 857          $this->assertArrayNotHasKey('glossary', $enabledfilters);
 858      }
 859  
 860      public function test_filter_get_globally_enabled_after_change() {
 861          $this->resetAfterTest();
 862          filter_set_global_state('glossary', TEXTFILTER_ON);
 863          $enabledfilters = filter_get_globally_enabled();
 864          $this->assertArrayHasKey('glossary', $enabledfilters);
 865      }
 866  
 867      public function test_filter_get_globally_enabled_filters_with_config() {
 868          $this->resetAfterTest();
 869          $this->remove_all_filters_from_config(); // Remove all filters.
 870          [
 871              'syscontext' => $syscontext,
 872              'childcontext' => $childcontext
 873          ] = $this->setup_available_in_context_tests();
 874          $this->remove_all_filters_from_config(); // Remove all filters.
 875  
 876          // Set few filters.
 877          filter_set_global_state('one', TEXTFILTER_ON);
 878          filter_set_global_state('three', TEXTFILTER_OFF, -1);
 879          filter_set_global_state('two', TEXTFILTER_DISABLED);
 880  
 881          // Set global config.
 882          filter_set_local_config('one', $syscontext->id, 'test1a', 'In root');
 883          filter_set_local_config('one', $syscontext->id, 'test1b', 'In root');
 884          filter_set_local_config('two', $syscontext->id, 'test2a', 'In root');
 885          filter_set_local_config('two', $syscontext->id, 'test2b', 'In root');
 886  
 887          // Set child config.
 888          filter_set_local_config('one', $childcontext->id, 'test1a', 'In child');
 889          filter_set_local_config('one', $childcontext->id, 'test1b', 'In child');
 890          filter_set_local_config('two', $childcontext->id, 'test2a', 'In child');
 891          filter_set_local_config('two', $childcontext->id, 'test2b', 'In child');
 892          filter_set_local_config('three', $childcontext->id, 'test3a', 'In child');
 893          filter_set_local_config('three', $childcontext->id, 'test3b', 'In child');
 894  
 895          // Check.
 896          $actual = filter_get_globally_enabled_filters_with_config();
 897          $this->assertCount(2, $actual);
 898          $this->assertEquals(['three', 'one'], array_keys($actual));     // Checks sortorder.
 899          $this->assertArrayHasKey('one', $actual);
 900          $this->assertArrayNotHasKey('two', $actual);
 901          $this->assertArrayHasKey('three', $actual);
 902          $this->assertEquals(['test1a' => 'In root', 'test1b' => 'In root'], $actual['one']);
 903          $this->assertEquals([], $actual['three']);
 904      }
 905  }