Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

   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_adminpresets;
  18  
  19  use stdClass;
  20  
  21  /**
  22   * Tests for the manager class.
  23   *
  24   * @package    core_adminpresets
  25   * @category   test
  26   * @copyright  2021 Sara Arjona (sara@moodle.com)
  27   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  28   * @coversDefaultClass \core_adminpresets\manager
  29   */
  30  class manager_test extends \advanced_testcase {
  31      /**
  32       * Test the behaviour of protected get_site_settings method.
  33       *
  34       * @covers ::get_site_settings
  35       * @covers ::get_settings
  36       */
  37      public function test_manager_get_site_settings(): void {
  38          global $DB;
  39  
  40          $this->resetAfterTest();
  41  
  42          // Login as admin, to access all the settings.
  43          $this->setAdminUser();
  44  
  45          $manager = new manager();
  46          $result = $manager->get_site_settings();
  47  
  48          // Check fullname is set into the none category.
  49          $this->assertInstanceOf(
  50                  '\core_adminpresets\local\setting\adminpresets_admin_setting_sitesettext',
  51                  $result['none']['fullname']
  52          );
  53          $this->assertEquals('PHPUnit test site', $result['none']['fullname']->get_value());
  54  
  55          // Check some of the config setting is present (they should be stored in the "none" category).
  56          $this->assertInstanceOf(
  57                  '\core_adminpresets\local\setting\adminpresets_admin_setting_configcheckbox',
  58                  $result['none']['enablecompletion']
  59          );
  60          $this->assertEquals(1, $result['none']['enablecompletion']->get_value());
  61  
  62          // Check some of the plugin config settings is present.
  63          $this->assertInstanceOf(
  64                  '\core_adminpresets\local\setting\adminpresets_admin_setting_configtext',
  65                  $result['folder']['maxsizetodownload']
  66          );
  67          $this->assertEquals(0, $result['folder']['maxsizetodownload']->get_value());
  68  
  69          // Set some of these values.
  70          $sitecourse = new stdClass();
  71          $sitecourse->id = 1;
  72          $sitecourse->fullname = 'New site fullname';
  73          $DB->update_record('course', $sitecourse);
  74  
  75          set_config('enablecompletion', 0);
  76          set_config('maxsizetodownload', 101, 'folder');
  77  
  78          // Check the new values are returned properly.
  79          $result = $manager->get_site_settings();
  80          // Site fullname.
  81          $this->assertInstanceOf(
  82                  '\core_adminpresets\local\setting\adminpresets_admin_setting_sitesettext',
  83                  $result['none']['fullname']
  84          );
  85          $this->assertEquals($sitecourse->fullname, $result['none']['fullname']->get_value());
  86          // Config setting.
  87          $this->assertInstanceOf(
  88                  '\core_adminpresets\local\setting\adminpresets_admin_setting_configcheckbox',
  89                  $result['none']['enablecompletion']
  90          );
  91          $this->assertEquals(0, $result['none']['enablecompletion']->get_value());
  92          // Plugin config settting.
  93          $this->assertInstanceOf(
  94                  '\core_adminpresets\local\setting\adminpresets_admin_setting_configtext',
  95                  $result['folder']['maxsizetodownload']
  96          );
  97          $this->assertEquals(101, $result['folder']['maxsizetodownload']->get_value());
  98      }
  99  
 100      /**
 101       * Test the behaviour of protected get_setting method.
 102       *
 103       * @covers ::get_setting
 104       * @covers ::get_settings_class
 105       */
 106      public function test_manager_get_setting(): void {
 107          $this->resetAfterTest();
 108  
 109          // Login as admin, to access all the settings.
 110          $this->setAdminUser();
 111  
 112          $adminroot = admin_get_root();
 113  
 114          // Check the adminpresets_xxxxx class is created properly when it exists.
 115          $settingpage = $adminroot->locate('optionalsubsystems');
 116          $settingdata = $settingpage->settings->enablebadges;
 117          $manager = new manager();
 118          $result = $manager->get_setting($settingdata, '');
 119          $this->assertInstanceOf('\core_adminpresets\local\setting\adminpresets_admin_setting_configcheckbox', $result);
 120          $this->assertNotEquals('core_adminpresets\local\setting\adminpresets_setting', get_class($result));
 121  
 122          // Check the mapped class is returned when no specific class exists and it exists in the mappings array.
 123          $settingpage = $adminroot->locate('h5psettings');
 124          $settingdata = $settingpage->settings->h5plibraryhandler;;
 125          $result = $manager->get_setting($settingdata, '');
 126          $this->assertInstanceOf('\core_adminpresets\local\setting\adminpresets_admin_setting_configselect', $result);
 127          $this->assertNotEquals(
 128                  'core_adminpresets\local\setting\adminpresets_admin_settings_h5plib_handler_select',
 129                  get_class($result)
 130          );
 131  
 132          // Check the mapped class is returned when no specific class exists and it exists in the mappings array.
 133          $settingpage = $adminroot->locate('modsettingquiz');
 134          $settingdata = $settingpage->settings->quizbrowsersecurity;;
 135          $result = $manager->get_setting($settingdata, '');
 136          $this->assertInstanceOf('\mod_quiz\adminpresets\adminpresets_mod_quiz_admin_setting_browsersecurity', $result);
 137          $this->assertNotEquals('core_adminpresets\local\setting\adminpresets_setting', get_class($result));
 138  
 139          // Check the adminpresets_setting class is returned when no specific class exists.
 140          $settingpage = $adminroot->locate('managecustomfields');
 141          $settingdata = $settingpage->settings->customfieldsui;;
 142          $result = $manager->get_setting($settingdata, '');
 143          $this->assertInstanceOf('\core_adminpresets\local\setting\adminpresets_setting', $result);
 144          $this->assertEquals('core_adminpresets\local\setting\adminpresets_setting', get_class($result));
 145      }
 146  
 147      /**
 148       * Test the behaviour of apply_preset() method when the given presetid doesn't exist.
 149       *
 150       * @covers ::apply_preset
 151       */
 152      public function test_apply_preset_unexisting_preset(): void {
 153          $this->resetAfterTest();
 154          $this->setAdminUser();
 155  
 156          // Create some presets.
 157          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 158          $presetid = $generator->create_preset();
 159  
 160          // Unexisting preset identifier.
 161          $unexistingid = $presetid * 2;
 162  
 163          $manager = new manager();
 164          $this->expectException(\moodle_exception::class);
 165          $manager->apply_preset($unexistingid);
 166      }
 167  
 168      /**
 169       * Test the behaviour of apply_preset() method.
 170       *
 171       * @covers ::apply_preset
 172       */
 173      public function test_apply_preset(): void {
 174          global $DB;
 175  
 176          $this->resetAfterTest();
 177          $this->setAdminUser();
 178  
 179          // Create a preset.
 180          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 181          $presetid = $generator->create_preset();
 182  
 183          $currentpresets = $DB->count_records('adminpresets');
 184          $currentitems = $DB->count_records('adminpresets_it');
 185          $currentadvitems = $DB->count_records('adminpresets_it_a');
 186          $currentplugins = $DB->count_records('adminpresets_plug');
 187          $currentapppresets = $DB->count_records('adminpresets_app');
 188          $currentappitems = $DB->count_records('adminpresets_app_it');
 189          $currentappadvitems = $DB->count_records('adminpresets_app_it_a');
 190          $currentappplugins = $DB->count_records('adminpresets_app_plug');
 191  
 192          // Set the config values (to confirm they change after applying the preset).
 193          set_config('enablebadges', 1);
 194          set_config('allowemojipicker', 1);
 195          set_config('mediawidth', '640', 'mod_lesson');
 196          set_config('maxanswers', '5', 'mod_lesson');
 197          set_config('maxanswers_adv', '1', 'mod_lesson');
 198          set_config('enablecompletion', 1);
 199          set_config('usecomments', 0);
 200  
 201          // Call the apply_preset method.
 202          $manager = new manager();
 203          $manager->apply_preset($presetid);
 204  
 205          // Check the preset applied has been added to database.
 206          $this->assertCount($currentapppresets + 1, $DB->get_records('adminpresets_app'));
 207          // Applied items: enablebadges@none, mediawitdh@mod_lesson and maxanswers@@mod_lesson.
 208          $this->assertCount($currentappitems + 3, $DB->get_records('adminpresets_app_it'));
 209          // Applied advanced items: maxanswers_adv@mod_lesson.
 210          $this->assertCount($currentappadvitems + 1, $DB->get_records('adminpresets_app_it_a'));
 211          // Applied plugins: enrol_guest and mod_glossary.
 212          $this->assertCount($currentappplugins + 2, $DB->get_records('adminpresets_app_plug'));
 213          // Check no new preset has been created.
 214          $this->assertCount($currentpresets, $DB->get_records('adminpresets'));
 215          $this->assertCount($currentitems, $DB->get_records('adminpresets_it'));
 216          $this->assertCount($currentadvitems, $DB->get_records('adminpresets_it_a'));
 217          $this->assertCount($currentplugins, $DB->get_records('adminpresets_plug'));
 218  
 219          // Check the setting values have changed accordingly with the ones defined in the preset.
 220          $this->assertEquals(0, get_config('core', 'enablebadges'));
 221          $this->assertEquals(900, get_config('mod_lesson', 'mediawidth'));
 222          $this->assertEquals(2, get_config('mod_lesson', 'maxanswers'));
 223          $this->assertEquals(0, get_config('mod_lesson', 'maxanswers_adv'));
 224  
 225          // These settings will never change.
 226          $this->assertEquals(1, get_config('core', 'allowemojipicker'));
 227          $this->assertEquals(1, get_config('core', 'enablecompletion'));
 228          $this->assertEquals(0, get_config('core', 'usecomments'));
 229  
 230          // Check the plugins visibility have changed accordingly with the ones defined in the preset.
 231          $enabledplugins = \core\plugininfo\enrol::get_enabled_plugins();
 232          $this->assertArrayNotHasKey('guest', $enabledplugins);
 233          $this->assertArrayHasKey('manual', $enabledplugins);
 234          $enabledplugins = \core\plugininfo\mod::get_enabled_plugins();
 235          $this->assertArrayNotHasKey('glossary', $enabledplugins);
 236          $this->assertArrayHasKey('assign', $enabledplugins);
 237          $enabledplugins = \core\plugininfo\qtype::get_enabled_plugins();
 238          $this->assertArrayHasKey('truefalse', $enabledplugins);
 239  
 240          // Check the presetid has been also stored in the lastpresetapplied config setting.
 241          $this->assertEquals($presetid, get_config('adminpresets', 'lastpresetapplied'));
 242  
 243          // Call apply_preset as a simulation, so it shouldn't be applied and lastpresetapplied should still be $presetid.
 244          $presetid2 = $generator->create_preset();
 245          $manager->apply_preset($presetid2, true);
 246          $this->assertEquals($presetid, get_config('adminpresets', 'lastpresetapplied'));
 247      }
 248  
 249  
 250      /**
 251       * Test the behaviour of export_preset() method.
 252       *
 253       * @covers ::export_preset
 254       * @dataProvider export_preset_provider
 255       *
 256       * @param bool $includesensible Whether the sensible settings should be exported too or not.
 257       * @param string $presetname Preset name.
 258       */
 259      public function test_export_preset(bool $includesensible = false, string $presetname = 'Export 1'): void {
 260          global $DB;
 261  
 262          $this->resetAfterTest();
 263          $this->setAdminUser();
 264  
 265          // Get current presets and items.
 266          $currentpresets = $DB->count_records('adminpresets');
 267          $currentadvitems = $DB->count_records('adminpresets_it_a');
 268  
 269          // Initialise some settings (to compare their values have been exported as expected).
 270          set_config('recaptchapublickey', 'abcde');
 271          set_config('enablebadges', '0');
 272          set_config('mediawidth', '900', 'mod_lesson');
 273          set_config('maxanswers', '2', 'mod_lesson');
 274          set_config('maxanswers_adv', '0', 'mod_lesson');
 275          set_config('defaultfeedback', '0', 'mod_lesson');
 276          set_config('defaultfeedback_adv', '1', 'mod_lesson');
 277  
 278          // Prepare the data to export preset.
 279          $data = [
 280              'name' => $presetname,
 281              'comments' => ['text' => 'This is a presets for testing export'],
 282              'author' => 'Super-Girl',
 283              'includesensiblesettings' => $includesensible,
 284          ];
 285  
 286          // Call the method to be tested.
 287          $manager = new manager();
 288          list($presetid, $settingsfound, $pluginsfound) = $manager->export_preset((object) $data);
 289  
 290          // Check the preset record has been created.
 291          $presets = $DB->get_records('adminpresets');
 292          $this->assertCount($currentpresets + 1, $presets);
 293          $this->assertArrayHasKey($presetid, $presets);
 294          $preset = $presets[$presetid];
 295          $this->assertEquals($presetname, $preset->name);
 296          $this->assertEquals(manager::NONCORE_PRESET, $preset->iscore);
 297  
 298          // Check the preset includes settings and plugins.
 299          $this->assertTrue($settingsfound);
 300          $this->assertTrue($pluginsfound);
 301  
 302          // Check the items, advanced attributes and plugins have been created.
 303          $this->assertGreaterThan(0, $DB->count_records('adminpresets_it', ['adminpresetid' => $presetid]));
 304          $this->assertGreaterThan($currentadvitems, $DB->count_records('adminpresets_it_a'));
 305          $this->assertGreaterThan(0, $DB->count_records('adminpresets_plug', ['adminpresetid' => $presetid]));
 306  
 307          // Check settings have been created with the expected values.
 308          $params = ['adminpresetid' => $presetid, 'plugin' => 'none', 'name' => 'enablebadges'];
 309          $setting = $DB->get_record('adminpresets_it', $params);
 310          $this->assertEquals('0', $setting->value);
 311  
 312          $params = ['adminpresetid' => $presetid, 'plugin' => 'mod_lesson', 'name' => 'mediawidth'];
 313          $setting = $DB->get_record('adminpresets_it', $params);
 314          $this->assertEquals('900', $setting->value);
 315  
 316          $params = ['adminpresetid' => $presetid, 'plugin' => 'mod_lesson', 'name' => 'maxanswers'];
 317          $setting = $DB->get_record('adminpresets_it', $params);
 318          $this->assertEquals('2', $setting->value);
 319          $params = ['itemid' => $setting->id, 'name' => 'maxanswers_adv'];
 320          $setting = $DB->get_record('adminpresets_it_a', $params);
 321          $this->assertEquals('0', $setting->value);
 322  
 323          $params = ['adminpresetid' => $presetid, 'plugin' => 'mod_lesson', 'name' => 'defaultfeedback'];
 324          $setting = $DB->get_record('adminpresets_it', $params);
 325          $this->assertEquals('0', $setting->value);
 326          $params = ['itemid' => $setting->id, 'name' => 'defaultfeedback_adv'];
 327          $setting = $DB->get_record('adminpresets_it_a', $params);
 328          $this->assertEquals('1', $setting->value);
 329  
 330          // Check plugins have been created with the expected values.
 331          $manager = \core_plugin_manager::instance();
 332          $plugintype = 'enrol';
 333          $plugins = $manager->get_present_plugins($plugintype);
 334          $enabledplugins = $manager->get_enabled_plugins($plugintype);
 335          foreach ($plugins as $pluginname => $unused) {
 336              $params = ['adminpresetid' => $presetid, 'plugin' => $plugintype, 'name' => $pluginname];
 337              $plugin = $DB->get_record('adminpresets_plug', $params);
 338              $enabled = (!empty($enabledplugins) && array_key_exists($pluginname, $enabledplugins));
 339              $this->assertEquals($enabled, (bool) $plugin->enabled);
 340          }
 341  
 342          // Check whether sensible settings have been exported or not.
 343          $params = ['adminpresetid' => $presetid, 'plugin' => 'none', 'name' => 'recaptchapublickey'];
 344          $recaptchasetting = $DB->get_record('adminpresets_it', $params);
 345          $params = ['adminpresetid' => $presetid, 'plugin' => 'none', 'name' => 'cronremotepassword'];
 346          $cronsetting = $DB->get_record('adminpresets_it', $params);
 347          if ($includesensible) {
 348              $this->assertEquals('abcde', $recaptchasetting->value);
 349              $this->assertNotFalse($cronsetting);
 350          } else {
 351              $this->assertFalse($recaptchasetting);
 352              $this->assertFalse($cronsetting);
 353          }
 354      }
 355  
 356      /**
 357       * Data provider for test_export_preset().
 358       *
 359       * @return array
 360       */
 361      public function export_preset_provider(): array {
 362          return [
 363              'Export settings and plugins, excluding sensible' => [
 364                  'includesensible' => false,
 365              ],
 366              'Export settings and plugins, including sensible' => [
 367                  'includesensible' => true,
 368              ],
 369              'Export settings and plugins, with Starter name (it should not be marked as core)' => [
 370                  'includesensible' => false,
 371                  'presetname' => 'Starter',
 372              ],
 373              'Export settings and plugins, with Full name (it should not be marked as core)' => [
 374                  'includesensible' => false,
 375                  'presetname' => 'Full',
 376              ],
 377          ];
 378      }
 379  
 380      /**
 381       * Test the behaviour of download_preset() method, when the given presetid doesn't exist.
 382       *
 383       * @covers ::download_preset
 384       */
 385      public function test_download_unexisting_preset(): void {
 386          $this->resetAfterTest();
 387          $this->setAdminUser();
 388  
 389          // Create some presets.
 390          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 391          $presetid = $generator->create_preset();
 392  
 393          // Unexisting preset identifier.
 394          $unexistingid = $presetid * 2;
 395  
 396          $manager = new manager();
 397          $this->expectException(\moodle_exception::class);
 398          $manager->download_preset($unexistingid);
 399      }
 400  
 401  
 402      /**
 403       * Test the behaviour of import_preset() method.
 404       *
 405       * @dataProvider import_preset_provider
 406       * @covers ::import_preset
 407       *
 408       * @param string $filecontents File content to import.
 409       * @param bool $expectedpreset Whether the preset should be created or not.
 410       * @param bool $expectedsettings Whether settings will be created or not.
 411       * @param bool $expectedplugins Whether plugins will be created or not.
 412       * @param bool $expecteddebugging Whether debugging message will be thrown or not.
 413       * @param string|null $expectedexception Expected exception class (if that's the case).
 414       * @param string|null $expectedpresetname Expected preset name.
 415       */
 416      public function test_import_preset(string $filecontents, bool $expectedpreset, bool $expectedsettings = false,
 417              bool $expectedplugins = false, bool $expecteddebugging = false, string $expectedexception = null,
 418              string $expectedpresetname = 'Imported preset'): void {
 419          global $DB;
 420  
 421          $this->resetAfterTest();
 422          $this->setAdminUser();
 423  
 424          $currentpresets = $DB->count_records('adminpresets');
 425          $currentitems = $DB->count_records('adminpresets_it');
 426          $currentadvitems = $DB->count_records('adminpresets_it_a');
 427  
 428          // Call the method to be tested.
 429          $manager = new manager();
 430          try {
 431              list($xml, $preset, $settingsfound, $pluginsfound) = $manager->import_preset($filecontents);
 432          } catch (\exception $e) {
 433              if ($expectedexception) {
 434                  $this->assertInstanceOf($expectedexception, $e);
 435              }
 436          } finally {
 437              if ($expecteddebugging) {
 438                  $this->assertDebuggingCalled();
 439              }
 440  
 441              if ($expectedpreset) {
 442                  // Check the preset record has been created.
 443                  $presets = $DB->get_records('adminpresets');
 444                  $this->assertCount($currentpresets + 1, $presets);
 445                  $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 446                  $this->assertArrayHasKey($preset->id, $presets);
 447                  $preset = $presets[$preset->id];
 448                  $this->assertEquals($expectedpresetname, $preset->name);
 449                  $this->assertEquals('http://demo.moodle', $preset->site);
 450                  $this->assertEquals('Ada Lovelace', $preset->author);
 451                  $this->assertEquals(manager::NONCORE_PRESET, $preset->iscore);
 452  
 453                  if ($expectedsettings) {
 454                      // Check the items have been created.
 455                      $items = $DB->get_records('adminpresets_it', ['adminpresetid' => $preset->id]);
 456                      $this->assertCount(4, $items);
 457                      $presetitems = [
 458                          'none' => [
 459                              'enablebadges' => 0,
 460                              'enableportfolios' => 1,
 461                              'allowemojipicker' => 1,
 462                          ],
 463                          'mod_lesson' => [
 464                              'mediawidth' => 900,
 465                              'maxanswers' => 2,
 466                          ],
 467                      ];
 468                      foreach ($items as $item) {
 469                          $this->assertArrayHasKey($item->name, $presetitems[$item->plugin]);
 470                          $this->assertEquals($presetitems[$item->plugin][$item->name], $item->value);
 471                      }
 472  
 473                      // Check the advanced attributes have been created.
 474                      $advitems = $DB->get_records('adminpresets_it_a');
 475                      $this->assertCount($currentadvitems + 1, $advitems);
 476                      $advitemfound = false;
 477                      foreach ($advitems as $advitem) {
 478                          if ($advitem->name == 'maxanswers_adv') {
 479                              $this->assertEmpty($advitem->value);
 480                              $advitemfound = true;
 481                          }
 482                      }
 483                      $this->assertTrue($advitemfound);
 484                  }
 485  
 486                  if ($expectedplugins) {
 487                      // Check the plugins have been created.
 488                      $plugins = $DB->get_records('adminpresets_plug', ['adminpresetid' => $preset->id]);
 489                      $this->assertCount(6, $plugins);
 490                      $presetplugins = [
 491                          'atto' => [
 492                              'html' => 1,
 493                          ],
 494                          'block' => [
 495                              'html' => 0,
 496                              'activity_modules' => 1,
 497                          ],
 498                          'mod' => [
 499                              'chat' => 0,
 500                              'data' => 0,
 501                              'lesson' => 1,
 502                          ],
 503                      ];
 504                      foreach ($plugins as $plugin) {
 505                          $this->assertArrayHasKey($plugin->name, $presetplugins[$plugin->plugin]);
 506                          $this->assertEquals($presetplugins[$plugin->plugin][$plugin->name], $plugin->enabled);
 507                      }
 508  
 509                  }
 510              } else {
 511                  // Check the preset nor the items are not created.
 512                  $this->assertCount($currentpresets, $DB->get_records('adminpresets'));
 513                  $this->assertCount($currentitems, $DB->get_records('adminpresets_it'));
 514                  $this->assertCount($currentadvitems, $DB->get_records('adminpresets_it_a'));
 515              }
 516          }
 517      }
 518  
 519      /**
 520       * Data provider for test_import_preset().
 521       *
 522       * @return array
 523       */
 524      public function import_preset_provider(): array {
 525          return [
 526              'Import settings from an empty file' => [
 527                  'filecontents' => '',
 528                  'expectedpreset' => false,
 529              ],
 530              'Import settings and plugins from a valid XML file' => [
 531                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_plugins.xml'),
 532                  'expectedpreset' => true,
 533                  'expectedsettings' => true,
 534                  'expectedplugins' => true,
 535              ],
 536              'Import only settings from a valid XML file' => [
 537                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings.xml'),
 538                  'expectedpreset' => true,
 539                  'expectedsettings' => true,
 540                  'expectedplugins' => false,
 541              ],
 542              'Import settings and plugins from a valid XML file with Starter name, which will be marked as non-core' => [
 543                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_starter_name.xml'),
 544                  'expectedpreset' => true,
 545                  'expectedsettings' => true,
 546                  'expectedplugins' => true,
 547                  'expecteddebugging' => false,
 548                  'expectedexception' => null,
 549                  'expectedpresetname' => 'Starter',
 550              ],
 551              'Import settings from an invalid XML file' => [
 552                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/invalid_xml_file.xml'),
 553                  'expectedpreset' => false,
 554                  'expectedsettings' => false,
 555                  'expectedplugins' => false,
 556                  'expecteddebugging' => false,
 557                  'expectedexception' => \Exception::class,
 558              ],
 559              'Import unexisting settings category' => [
 560                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_category.xml'),
 561                  'expectedpreset' => false,
 562                  'expectedsettings' => false,
 563                  'expectedplugins' => false,
 564              ],
 565              'Import unexisting setting' => [
 566                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/unexisting_setting.xml'),
 567                  'expectedpreset' => false,
 568                  'expectedsettings' => false,
 569                  'expectedplugins' => false,
 570                  'expecteddebugging' => true,
 571              ],
 572              'Import valid settings with one unexisting setting too' => [
 573                  'filecontents' => file_get_contents(__DIR__ . '/fixtures/import_settings_with_unexisting_setting.xml'),
 574                  'expectedpreset' => true,
 575                  'expectedsettings' => false,
 576                  'expectedplugins' => false,
 577                  'expecteddebugging' => true,
 578              ],
 579          ];
 580      }
 581  
 582  
 583      /**
 584       * Test the behaviour of delete_preset() method when the preset id doesn't exist.
 585       *
 586       * @covers ::delete_preset
 587       */
 588      public function test_delete_preset_unexisting_preset(): void {
 589  
 590          $this->resetAfterTest();
 591          $this->setAdminUser();
 592  
 593          // Create some presets.
 594          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 595          $presetid = $generator->create_preset(['name' => 'Preset 1']);
 596  
 597          // Unexisting preset identifier.
 598          $unexistingid = $presetid * 2;
 599  
 600          $manager = new manager();
 601  
 602          $this->expectException(\moodle_exception::class);
 603          $manager->delete_preset($unexistingid);
 604      }
 605  
 606      /**
 607       * Test the behaviour of delete_preset() method.
 608       *
 609       * @covers ::delete_preset
 610       */
 611      public function test_delete_preset(): void {
 612          global $DB;
 613  
 614          $this->resetAfterTest();
 615          $this->setAdminUser();
 616  
 617          // Create some presets.
 618          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 619          $presetid1 = $generator->create_preset(['name' => 'Preset 1', 'applypreset' => true]);
 620          $presetid2 = $generator->create_preset(['name' => 'Preset 2']);
 621  
 622          $currentpresets = $DB->count_records('adminpresets');
 623          $currentitems = $DB->count_records('adminpresets_it');
 624          $currentadvitems = $DB->count_records('adminpresets_it_a');
 625          $currentplugins = $DB->count_records('adminpresets_plug');
 626  
 627          // Only preset1 has been applied.
 628          $this->assertCount(1, $DB->get_records('adminpresets_app'));
 629          // Only the preset1 settings that have changed: enablebadges, mediawidth and maxanswers.
 630          $this->assertCount(3, $DB->get_records('adminpresets_app_it'));
 631          // Only the preset1 advanced settings that have changed: maxanswers_adv.
 632          $this->assertCount(1, $DB->get_records('adminpresets_app_it_a'));
 633          // Only the preset1 plugins that have changed: enrol_guest and mod_glossary.
 634          $this->assertCount(2, $DB->get_records('adminpresets_app_plug'));
 635  
 636          // Call the method to be tested.
 637          $manager = new manager();
 638          $manager->delete_preset($presetid1);
 639  
 640          // Check the preset data has been removed.
 641          $presets = $DB->get_records('adminpresets');
 642          $this->assertCount($currentpresets - 1, $presets);
 643          $preset = reset($presets);
 644          $this->assertArrayHasKey($presetid2, $presets);
 645          // Check preset items.
 646          $this->assertCount($currentitems - 4, $DB->get_records('adminpresets_it'));
 647          $this->assertCount(0, $DB->get_records('adminpresets_it', ['adminpresetid' => $presetid1]));
 648          // Check preset advanced items.
 649          $this->assertCount($currentadvitems - 1, $DB->get_records('adminpresets_it_a'));
 650          // Check preset plugins.
 651          $this->assertCount($currentplugins - 3, $DB->get_records('adminpresets_plug'));
 652          $this->assertCount(0, $DB->get_records('adminpresets_plug', ['adminpresetid' => $presetid1]));
 653          // Check preset applied tables are empty now.
 654          $this->assertCount(0, $DB->get_records('adminpresets_app'));
 655          $this->assertCount(0, $DB->get_records('adminpresets_app_it'));
 656          $this->assertCount(0, $DB->get_records('adminpresets_app_it_a'));
 657          $this->assertCount(0, $DB->get_records('adminpresets_app_plug'));
 658      }
 659  
 660      /**
 661       * Test the behaviour of revert_preset() method when the preset applied id doesn't exist.
 662       *
 663       * @covers ::revert_preset
 664       */
 665      public function test_revert_preset_unexisting_presetapp(): void {
 666          global $DB;
 667  
 668          $this->resetAfterTest();
 669          $this->setAdminUser();
 670  
 671          // Create a preset and apply it.
 672          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 673          $presetid = $generator->create_preset(['applypreset' => true]);
 674          $presetappid = $DB->get_field('adminpresets_app', 'id', ['adminpresetid' => $presetid]);
 675  
 676          // Unexisting applied preset identifier.
 677          $unexistingid = $presetappid * 2;
 678  
 679          $manager = new manager();
 680          $this->expectException(\moodle_exception::class);
 681          $manager->revert_preset($unexistingid);
 682      }
 683  
 684      /**
 685       * Test the behaviour of revert_preset() method.
 686       *
 687       * @covers ::revert_preset
 688       */
 689      public function test_revert_preset(): void {
 690          global $DB;
 691  
 692          $this->resetAfterTest();
 693          $this->setAdminUser();
 694  
 695          // Set the config values (to confirm they change after applying the preset).
 696          set_config('enablebadges', 1);
 697          set_config('allowemojipicker', 1);
 698          set_config('mediawidth', '640', 'mod_lesson');
 699          set_config('maxanswers', '5', 'mod_lesson');
 700          set_config('maxanswers_adv', '1', 'mod_lesson');
 701          set_config('enablecompletion', 1);
 702          set_config('usecomments', 0);
 703  
 704          // Create a preset and apply it.
 705          $generator = $this->getDataGenerator()->get_plugin_generator('core_adminpresets');
 706          $presetid = $generator->create_preset(['applypreset' => true]);
 707          $presetappid = $DB->get_field('adminpresets_app', 'id', ['adminpresetid' => $presetid]);
 708  
 709          $currentpresets = $DB->count_records('adminpresets');
 710          $currentitems = $DB->count_records('adminpresets_it');
 711          $currentadvitems = $DB->count_records('adminpresets_it_a');
 712          $currentplugins = $DB->count_records('adminpresets_plug');
 713          $this->assertCount(1, $DB->get_records('adminpresets_app'));
 714          $this->assertCount(3, $DB->get_records('adminpresets_app_it'));
 715          $this->assertCount(1, $DB->get_records('adminpresets_app_it_a'));
 716          $this->assertCount(2, $DB->get_records('adminpresets_app_plug'));
 717  
 718          // Check the setttings have changed accordingly after applying the preset.
 719          $this->assertEquals(0, get_config('core', 'enablebadges'));
 720          $this->assertEquals(900, get_config('mod_lesson', 'mediawidth'));
 721          $this->assertEquals(2, get_config('mod_lesson', 'maxanswers'));
 722          $this->assertEquals(1, get_config('core', 'allowemojipicker'));
 723          $this->assertEquals(1, get_config('core', 'enablecompletion'));
 724          $this->assertEquals(0, get_config('core', 'usecomments'));
 725  
 726          // Check the plugins visibility have changed accordingly with the ones defined in the preset.
 727          $enabledplugins = \core\plugininfo\enrol::get_enabled_plugins();
 728          $this->assertArrayNotHasKey('guest', $enabledplugins);
 729          $enabledplugins = \core\plugininfo\mod::get_enabled_plugins();
 730          $this->assertArrayNotHasKey('glossary', $enabledplugins);
 731          $enabledplugins = \core\plugininfo\qtype::get_enabled_plugins();
 732          $this->assertArrayHasKey('truefalse', $enabledplugins);
 733  
 734          // Call the method to be tested.
 735          $manager = new manager();
 736          list($presetapp, $rollback, $failures) = $manager->revert_preset($presetappid);
 737  
 738          // Check the preset applied has been reverted (so the records in _appXX tables have been removed).
 739          $this->assertNotEmpty($presetapp);
 740          $this->assertNotEmpty($rollback);
 741          $this->assertEmpty($failures);
 742          $this->assertCount(0, $DB->get_records('adminpresets_app'));
 743          $this->assertCount(0, $DB->get_records('adminpresets_app_it'));
 744          $this->assertCount(0, $DB->get_records('adminpresets_app_it_a'));
 745          $this->assertCount(0, $DB->get_records('adminpresets_app_plug'));
 746          // Check the preset data hasn't changed.
 747          $this->assertCount($currentpresets, $DB->get_records('adminpresets'));
 748          $this->assertCount($currentitems, $DB->get_records('adminpresets_it'));
 749          $this->assertCount($currentadvitems, $DB->get_records('adminpresets_it_a'));
 750          $this->assertCount($currentplugins, $DB->get_records('adminpresets_plug'));
 751  
 752          // Check the setting values have been reverted accordingly.
 753          $this->assertEquals(1, get_config('core', 'enablebadges'));
 754          $this->assertEquals(640, get_config('mod_lesson', 'mediawidth'));
 755          $this->assertEquals(5, get_config('mod_lesson', 'maxanswers'));
 756          $this->assertEquals(1, get_config('mod_lesson', 'maxanswers_adv'));
 757          // These settings won't change, regardless if they are posted to the form.
 758          $this->assertEquals(1, get_config('core', 'allowemojipicker'));
 759          $this->assertEquals(1, get_config('core', 'enablecompletion'));
 760          $this->assertEquals(0, get_config('core', 'usecomments'));
 761  
 762          // Check the plugins visibility have been reverted accordingly.
 763          $enabledplugins = \core\plugininfo\enrol::get_enabled_plugins();
 764          $this->assertArrayHasKey('guest', $enabledplugins);
 765          $enabledplugins = \core\plugininfo\mod::get_enabled_plugins();
 766          $this->assertArrayHasKey('glossary', $enabledplugins);
 767          // This plugin won't change (because it had the same value than before the preset was applied).
 768          $enabledplugins = \core\plugininfo\qtype::get_enabled_plugins();
 769          $this->assertArrayHasKey('truefalse', $enabledplugins);
 770      }
 771  }