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.
   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 mod_data;
  18  
  19  use file_archive;
  20  use stdClass;
  21  use zip_archive;
  22  
  23  /**
  24   * Preset tests class for mod_data.
  25   *
  26   * @package    mod_data
  27   * @category   test
  28   * @copyright  2022 Sara Arjona <sara@moodle.com>
  29   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   * @coversDefaultClass \mod_data\preset
  31   */
  32  class preset_test extends \advanced_testcase {
  33  
  34      /**
  35       * Test for static create_from_plugin method.
  36       *
  37       * @covers ::create_from_plugin
  38       */
  39      public function test_create_from_plugin() {
  40          $this->resetAfterTest();
  41          $this->setAdminUser();
  42  
  43          // Check create_from_plugin is working as expected when an existing plugin is given.
  44          $pluginname = 'imagegallery';
  45          $result = preset::create_from_plugin(null, $pluginname);
  46          $this->assertTrue($result->isplugin);
  47          $this->assertEquals(get_string('modulename', "datapreset_$pluginname"), $result->name);
  48          $this->assertEquals($pluginname, $result->shortname);
  49          $this->assertEquals(get_string('modulename_help', "datapreset_$pluginname"), $result->description);
  50          $this->assertEmpty($result->get_userid());
  51          $this->assertEmpty($result->storedfile);
  52          $this->assertNull($result->get_path());
  53  
  54          // Check create_from_plugin is working as expected when an unexisting plugin is given.
  55          $pluginname = 'unexisting';
  56          $result = preset::create_from_plugin(null, $pluginname);
  57          $this->assertNull($result);
  58      }
  59  
  60      /**
  61       * Test for static create_from_storedfile method.
  62       *
  63       * @covers ::create_from_storedfile
  64       */
  65      public function test_create_from_storedfile() {
  66          global $USER;
  67  
  68          $this->resetAfterTest();
  69          $this->setAdminUser();
  70  
  71          // Create a course and a database activity.
  72          $course = $this->getDataGenerator()->create_course();
  73          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
  74          $manager = manager::create_from_instance($activity);
  75  
  76          // Create a saved preset.
  77          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
  78          $record = (object) [
  79              'name' => 'Testing preset name',
  80              'description' => 'Testing preset description',
  81          ];
  82          $plugingenerator->create_preset($activity, $record);
  83          $savedpresets = $manager->get_available_saved_presets();
  84          $savedpreset = reset($savedpresets);
  85  
  86          // Check create_from_storedfile is working as expected with a valid preset file.
  87          $result = preset::create_from_storedfile($manager, $savedpreset->storedfile);
  88          $this->assertFalse($result->isplugin);
  89          $this->assertEquals($record->name, $result->name);
  90          $this->assertEquals($record->name, $result->shortname);
  91          $this->assertEquals($record->description, $result->description);
  92          $this->assertEquals($savedpreset->storedfile->get_userid(), $result->get_userid());
  93          $this->assertNotEmpty($result->storedfile);
  94          $this->assertEquals('/' . $record->name . '/', $result->get_path());
  95  
  96          // Check create_from_storedfile is not creating a preset object when an invalid file is given.
  97          $draftid = file_get_unused_draft_itemid();
  98          $filerecord = [
  99              'component' => 'user',
 100              'filearea' => 'draft',
 101              'contextid' => \context_user::instance($USER->id)->id,
 102              'itemid' => $draftid,
 103              'filename' => 'preset.xml',
 104              'filepath' => '/'
 105          ];
 106          $fs = get_file_storage();
 107          $file = $fs->create_file_from_string($filerecord, 'This is the file content');
 108          $result = preset::create_from_storedfile($manager, $file);
 109          $this->assertNull($result);
 110      }
 111  
 112      /**
 113       * Test for static create_from_instance method.
 114       *
 115       * @covers ::create_from_instance
 116       */
 117      public function test_create_from_instance() {
 118          $this->resetAfterTest();
 119          $this->setAdminUser();
 120  
 121          // Create a course and a database activity.
 122          $course = $this->getDataGenerator()->create_course();
 123          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 124          $manager = manager::create_from_instance($activity);
 125  
 126          // Create a saved preset.
 127          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 128          $record = (object) [
 129              'name' => 'Testing preset name',
 130              'description' => 'Testing preset description',
 131          ];
 132          $plugingenerator->create_preset($activity, $record);
 133          $savedpresets = $manager->get_available_saved_presets();
 134          $savedpreset = reset($savedpresets);
 135  
 136          // Check create_from_instance is working as expected when a preset with this name exists.
 137          $result = preset::create_from_instance($manager, $record->name, $record->description);
 138          $this->assertFalse($result->isplugin);
 139          $this->assertEquals($record->name, $result->name);
 140          $this->assertEquals($record->name, $result->shortname);
 141          $this->assertEquals($record->description, $result->description);
 142          $this->assertEquals($savedpreset->storedfile->get_userid(), $result->get_userid());
 143          $this->assertNotEmpty($result->storedfile);
 144          $this->assertEquals('/' . $record->name . '/', $result->get_path());
 145  
 146          // Check create_from_instance is working as expected when there is no preset with the given name.
 147          $presetname = 'Unexisting preset';
 148          $presetdescription = 'This is the description for the unexisting preset';
 149          $result = preset::create_from_instance($manager, $presetname, $presetdescription);
 150          $this->assertFalse($result->isplugin);
 151          $this->assertEquals($presetname, $result->name);
 152          $this->assertEquals($presetname, $result->shortname);
 153          $this->assertEquals($presetdescription, $result->description);
 154          $this->assertEmpty($result->get_userid());
 155          $this->assertEmpty($result->storedfile);
 156          $this->assertEquals('/' . $presetname . '/', $result->get_path());
 157      }
 158  
 159      /**
 160       * Test for static create_from_fullname method.
 161       *
 162       * @covers ::create_from_fullname
 163       */
 164      public function test_create_from_fullname() {
 165          $this->resetAfterTest();
 166          $this->setAdminUser();
 167  
 168          // Create a course and a database activity.
 169          $course = $this->getDataGenerator()->create_course();
 170          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 171          $manager = manager::create_from_instance($activity);
 172  
 173          // Create a saved preset.
 174          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 175          $record = (object) [
 176              'name' => 'Testing preset name',
 177              'description' => 'Testing preset description',
 178          ];
 179          $savedpreset = $plugingenerator->create_preset($activity, $record);
 180  
 181          // Check instantiate from plugin.
 182          $pluginname = 'imagegallery';
 183          $fullname = '0/imagegallery';
 184          $result = preset::create_from_fullname($manager, $fullname);
 185          $this->assertTrue($result->isplugin);
 186          $this->assertEquals(get_string('modulename', "datapreset_$pluginname"), $result->name);
 187          $this->assertEquals($pluginname, $result->shortname);
 188          $this->assertEquals(get_string('modulename_help', "datapreset_$pluginname"), $result->description);
 189          $this->assertEmpty($result->get_userid());
 190          $this->assertEmpty($result->storedfile);
 191          $this->assertNull($result->get_path());
 192  
 193          // Check instantiate from user preset
 194          // Check create_from_instance is working as expected when a preset with this name exists.
 195          $fullname = $savedpreset->get_userid() . '/' . $savedpreset->name;
 196          $result = preset::create_from_fullname($manager, $fullname);
 197          $this->assertFalse($result->isplugin);
 198          $this->assertEquals($savedpreset->name, $result->name);
 199          $this->assertEquals($savedpreset->shortname, $result->shortname);
 200          $this->assertEquals($savedpreset->description, $savedpreset->description);
 201          $this->assertEquals($savedpreset->storedfile->get_userid(), $result->get_userid());
 202          $this->assertNotEmpty($result->storedfile);
 203          $this->assertEquals('/' . $savedpreset->name . '/', $result->get_path());
 204      }
 205  
 206      /**
 207       * Test for the save a preset method when the preset hasn't been saved before.
 208       *
 209       * @covers ::save
 210       */
 211      public function test_save_new_preset() {
 212          $this->resetAfterTest();
 213          $this->setAdminUser();
 214  
 215          // Save should return false when trying to save a plugin preset.
 216          $preset = preset::create_from_plugin(null, 'imagegallery');
 217          $result = $preset->save();
 218          $this->assertFalse($result);
 219  
 220          // Create a course and a database activity.
 221          $course = $this->getDataGenerator()->create_course();
 222          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 223          $manager = manager::create_from_instance($activity);
 224  
 225          // Add a field to the activity.
 226          $fieldrecord = new stdClass();
 227          $fieldrecord->name = 'field-1';
 228          $fieldrecord->type = 'text';
 229          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 230          $datagenerator->create_field($fieldrecord, $activity);
 231  
 232          // Create a saved preset.
 233          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 234          $record = (object) [
 235              'name' => 'Testing preset name',
 236              'description' => 'Testing preset description',
 237          ];
 238          $plugingenerator->create_preset($activity, $record);
 239  
 240          // Save should return false when trying to save an existing saved preset.
 241          $preset = preset::create_from_instance($manager, $record->name, $record->description);
 242          $result = $preset->save();
 243          $this->assertFalse($result);
 244  
 245          // The preset should be saved when it's new and there is no any other having the same name.
 246          $savedpresets = $manager->get_available_saved_presets();
 247          $this->assertCount(1, $savedpresets);
 248          $presetname = 'New preset';
 249          $presetdescription = 'This is the description for the new preset';
 250          $preset = preset::create_from_instance($manager, $presetname, $presetdescription);
 251          $result = $preset->save();
 252          $this->assertTrue($result);
 253          // Check the preset has been created.
 254          $savedpresets = $manager->get_available_saved_presets();
 255          $this->assertCount(2, $savedpresets);
 256          $savedpresetsnames = array_map(function($preset) {
 257              return $preset->name;
 258          }, $savedpresets);
 259          $this->assertContains($presetname, $savedpresetsnames);
 260      }
 261  
 262      /**
 263       * Test for the save a preset method when is an existing preset that has been saved before.
 264       *
 265       * @covers ::save
 266       */
 267      public function test_save_existing_preset() {
 268          $this->resetAfterTest();
 269          $this->setAdminUser();
 270  
 271          // Create a course and a database activity.
 272          $course = $this->getDataGenerator()->create_course();
 273          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 274          $manager = manager::create_from_instance($activity);
 275  
 276          // Add a field to the activity.
 277          $fieldrecord = new stdClass();
 278          $fieldrecord->name = 'field-1';
 279          $fieldrecord->type = 'text';
 280          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 281          $datagenerator->create_field($fieldrecord, $activity);
 282  
 283          // Create a saved preset.
 284          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 285          $record = (object) [
 286              'name' => 'Testing preset name',
 287              'description' => 'Testing preset description',
 288          ];
 289          $oldpresetname = $record->name;
 290          $plugingenerator->create_preset($activity, $record);
 291  
 292          // Save should return false when trying to save an existing preset.
 293          $preset = preset::create_from_instance($manager, $record->name, $record->description);
 294          $result = $preset->save();
 295          $this->assertFalse($result);
 296          // Check no new preset has been created.
 297          $this->assertCount(1, $manager->get_available_saved_presets());
 298  
 299          // Save should overwrite existing preset if name or description have changed.
 300          $preset->name = 'New preset name';
 301          $preset->description = 'New preset description';
 302          $result = $preset->save();
 303          $this->assertTrue($result);
 304          // Check the preset files have been renamed.
 305          $presetfiles = array_merge(array_values(manager::TEMPLATES_LIST), ['preset.xml', '.']);
 306          foreach ($presetfiles as $templatefile) {
 307              $file = preset::get_file($preset->get_path(), $templatefile);
 308              $this->assertNotNull($file);
 309          }
 310          // Check old preset files have been removed.
 311          $oldpath = "{$oldpresetname}";
 312          foreach ($presetfiles as $templatefile) {
 313              $file = preset::get_file($oldpath, $templatefile);
 314              $this->assertNull($file);
 315          }
 316  
 317          // Check no new preset has been created.
 318          $savedpresets = $manager->get_available_saved_presets();
 319          $this->assertCount(1, $savedpresets);
 320          // Check the preset has the expected values.
 321          $savedpreset = reset($savedpresets);
 322          $this->assertEquals($preset->name, $savedpreset->name);
 323          $this->assertEquals($preset->description, $savedpreset->description);
 324          $this->assertNotEmpty($preset->storedfile);
 325          // Check the storedfile has been updated properly.
 326          $this->assertEquals($preset->name, trim($savedpreset->storedfile->get_filepath(), '/'));
 327  
 328          // Create another saved preset with empty description.
 329          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 330          $record = (object) [
 331              'name' => 'Testing preset 2',
 332          ];
 333          $plugingenerator->create_preset($activity, $record);
 334          $this->assertCount(2, $manager->get_available_saved_presets());
 335          // Description should be saved too when it was empty in the original preset and a new value is assigned to it.
 336          $preset = preset::create_from_instance($manager, $record->name);
 337          $preset->description = 'New preset description';
 338          $result = $preset->save();
 339          $this->assertTrue($result);
 340          $savedpresets = $manager->get_available_saved_presets();
 341          $this->assertCount(2, $savedpresets);
 342          foreach ($savedpresets as $savedpreset) {
 343              if ($savedpreset->name == $record->name) {
 344                  $this->assertEquals($preset->description, $savedpreset->description);
 345              }
 346          }
 347      }
 348  
 349      /**
 350       * Test for the export a preset method.
 351       *
 352       * @covers ::export
 353       */
 354      public function test_export() {
 355          $this->resetAfterTest();
 356          $this->setAdminUser();
 357  
 358          // Export should return empty string when trying to export a plugin preset.
 359          $preset = preset::create_from_plugin(null, 'imagegallery');
 360          $result = $preset->export();
 361          $this->assertEmpty($result);
 362  
 363          // Create a course and a database activity.
 364          $course = $this->getDataGenerator()->create_course();
 365          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 366          $manager = manager::create_from_instance($activity);
 367  
 368          // Add a field to the activity.
 369          $fieldrecord = new stdClass();
 370          $fieldrecord->name = 'field-1';
 371          $fieldrecord->type = 'text';
 372          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 373          $datagenerator->create_field($fieldrecord, $activity);
 374  
 375          // For now, default templates are not created automatically. This will be changed in MDL-75234.
 376          foreach (manager::TEMPLATES_LIST as $templatename => $notused) {
 377              data_generate_default_template($activity, $templatename);
 378          }
 379  
 380          $preset = preset::create_from_instance($manager, $activity->name);
 381          $result = $preset->export();
 382          $presetfilenames = array_merge(array_values(manager::TEMPLATES_LIST), ['preset.xml']);
 383  
 384          $ziparchive = new zip_archive();
 385          $ziparchive->open($result, file_archive::OPEN);
 386          $files = $ziparchive->list_files();
 387          foreach ($files as $file) {
 388              $this->assertContains($file->pathname, $presetfilenames);
 389  
 390              // Check the file is not empty (except CSS, JS and listtemplateheader/footer files which are empty by default).
 391              $extension = pathinfo($file->pathname, PATHINFO_EXTENSION);
 392              $ishtmlorxmlfile = in_array($extension, ['html', 'xml']);
 393  
 394              $expectedemptyfiles = array_intersect_key(manager::TEMPLATES_LIST, array_flip([
 395                  'listtemplateheader',
 396                  'listtemplatefooter',
 397                  'rsstitletemplate',
 398              ]));
 399  
 400              if ($ishtmlorxmlfile && !in_array($file->pathname, $expectedemptyfiles)) {
 401                  $this->assertGreaterThan(0, $file->size);
 402              } else {
 403                  $this->assertEquals(0, $file->size);
 404              }
 405          }
 406          $ziparchive->close();
 407      }
 408  
 409      /**
 410       * Test for get_userid().
 411       *
 412       * @covers ::get_userid
 413       */
 414      public function test_get_userid() {
 415          $this->resetAfterTest();
 416  
 417          $course = $this->getDataGenerator()->create_course();
 418          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 419          $user = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 420          $this->setUser($user);
 421  
 422          // Check userid is null for plugin preset.
 423          $manager = manager::create_from_instance($activity);
 424          $pluginpresets = $manager->get_available_plugin_presets();
 425          $pluginpreset = reset($pluginpresets);
 426          $this->assertNull($pluginpreset->get_userid());
 427  
 428          // Check userid meets the user that has created the preset when it's a saved preset.
 429          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 430          $savedpreset = (object) [
 431              'name' => 'Preset created by teacher',
 432          ];
 433          $plugingenerator->create_preset($activity, $savedpreset);
 434          $savedpresets = $manager->get_available_saved_presets();
 435          $savedpreset = reset($savedpresets);
 436          $this->assertEquals($user->id, $savedpreset->get_userid());
 437  
 438          // Check userid is null when preset hasn't any file associated.
 439          $preset = preset::create_from_instance($manager, 'Unexisting preset');
 440          $this->assertNull($preset->get_userid());
 441      }
 442  
 443      /**
 444       * Test for get_path().
 445       *
 446       * @covers ::get_path
 447       */
 448      public function test_get_path() {
 449          $this->resetAfterTest();
 450          $this->setAdminUser();
 451  
 452          $course = $this->getDataGenerator()->create_course();
 453          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 454  
 455          // Check path is null for plugin preset.
 456          $manager = manager::create_from_instance($activity);
 457          $pluginpresets = $manager->get_available_plugin_presets();
 458          $pluginpreset = reset($pluginpresets);
 459          $this->assertNull($pluginpreset->get_path());
 460  
 461          // Check path meets expected value when it's a saved preset.
 462          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 463          $savedpreset = (object) [
 464              'name' => 'Saved preset',
 465          ];
 466          $plugingenerator->create_preset($activity, $savedpreset);
 467          $savedpresets = $manager->get_available_saved_presets();
 468          $savedpreset = reset($savedpresets);
 469          $this->assertEquals("/{$savedpreset->name}/", $savedpreset->get_path());
 470  
 471          // Check path is /presetname/ when preset hasn't any file associated.
 472          $presetname = 'Unexisting preset';
 473          $preset = preset::create_from_instance($manager, $presetname);
 474          $this->assertEquals("/{$presetname}/", $preset->get_path());
 475      }
 476  
 477      /**
 478       * Test for is_directory_a_preset().
 479       *
 480       * @dataProvider is_directory_a_preset_provider
 481       * @covers ::is_directory_a_preset
 482       * @param string $directory
 483       * @param bool $expected
 484       */
 485      public function test_is_directory_a_preset(string $directory, bool $expected): void {
 486          $this->resetAfterTest();
 487          $this->setAdminUser();
 488  
 489          $result = preset::is_directory_a_preset($directory);
 490          $this->assertEquals($expected, $result);
 491      }
 492  
 493      /**
 494       * Data provider for test_is_directory_a_preset().
 495       *
 496       * @return array
 497       */
 498      public function is_directory_a_preset_provider(): array {
 499          global $CFG;
 500  
 501          return [
 502              'Valid preset directory' => [
 503                  'directory' => $CFG->dirroot . '/mod/data/preset/imagegallery',
 504                  'expected' => true,
 505              ],
 506              'Invalid preset directory' => [
 507                  'directory' => $CFG->dirroot . '/mod/data/field/checkbox',
 508                  'expected' => false,
 509              ],
 510              'Unexisting preset directory' => [
 511                  'directory' => $CFG->dirroot . 'unexistingdirectory',
 512                  'expected' => false,
 513              ],
 514          ];
 515      }
 516  
 517      /**
 518       * Test for get_name_from_plugin().
 519       *
 520       * @covers ::get_name_from_plugin
 521       */
 522      public function test_get_name_from_plugin() {
 523          $this->resetAfterTest();
 524          $this->setAdminUser();
 525  
 526          // The expected name for plugins with modulename in lang is this value.
 527          $name = preset::get_name_from_plugin('imagegallery');
 528          $this->assertEquals('Image gallery', $name);
 529  
 530          // However, if the plugin doesn't exist or the modulename is not defined, the preset shortname will be returned.
 531          $presetshortname = 'nonexistingpreset';
 532          $name = preset::get_name_from_plugin($presetshortname);
 533          $this->assertEquals($presetshortname, $name);
 534      }
 535  
 536      /**
 537       * Test for get_description_from_plugin().
 538       *
 539       * @covers ::get_description_from_plugin
 540       */
 541      public function test_get_description_from_plugin() {
 542          $this->resetAfterTest();
 543          $this->setAdminUser();
 544  
 545          // The expected name for plugins with modulename in lang is this value.
 546          $description = preset::get_description_from_plugin('imagegallery');
 547          $this->assertEquals('Use this preset to collect images.', $description);
 548  
 549          // However, if the plugin doesn't exist or the modulename is not defined, empty string will be returned.
 550          $presetshortname = 'nonexistingpreset';
 551          $description = preset::get_description_from_plugin($presetshortname);
 552          $this->assertEmpty($description);
 553      }
 554  
 555      /**
 556       * Test for generate_preset_xml().
 557       *
 558       * @covers ::generate_preset_xml
 559       * @dataProvider generate_preset_xml_provider
 560       * @param array $params activity config settings
 561       * @param string|null $description preset description
 562       */
 563      public function test_generate_preset_xml(array $params, ?string $description) {
 564          $this->resetAfterTest();
 565          $this->setAdminUser();
 566  
 567          // Make accessible the method.
 568          $reflection = new \ReflectionClass(preset::class);
 569          $method = $reflection->getMethod('generate_preset_xml');
 570          $method->setAccessible(true);
 571  
 572          // The method should return empty string when trying to generate preset.xml for a plugin preset.
 573          $preset = preset::create_from_plugin(null, 'imagegallery');
 574          $result = $method->invokeArgs($preset, []);
 575          $this->assertEmpty($result);
 576  
 577          // Create a course and a database activity.
 578          $course = $this->getDataGenerator()->create_course();
 579          $activity = $this->getDataGenerator()->create_module(manager::MODULE, array_merge(['course' => $course], $params));
 580  
 581          // Add a field to the activity.
 582          $fieldrecord = new stdClass();
 583          $fieldrecord->name = 'field-1';
 584          $fieldrecord->type = 'text';
 585          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 586          $datagenerator->create_field($fieldrecord, $activity);
 587  
 588          $manager = manager::create_from_instance($activity);
 589          $preset = preset::create_from_instance($manager, $activity->name, $description);
 590  
 591          // Call the generate_preset_xml method.
 592          $result = $method->invokeArgs($preset, []);
 593          // Check is a valid XML.
 594          $parsedxml = simplexml_load_string($result);
 595          // Check the description has the expected value.
 596          $this->assertEquals($description, strval($parsedxml->description));
 597          // Check settings have the expected values.
 598          foreach ($params as $paramname => $paramvalue) {
 599              $this->assertEquals($paramvalue, strval($parsedxml->settings->{$paramname}));
 600          }
 601          // Check field have the expected values.
 602          $this->assertEquals($fieldrecord->name, strval($parsedxml->field->name));
 603          $this->assertEquals($fieldrecord->type, strval($parsedxml->field->type));
 604      }
 605  
 606      /**
 607       * Data provider for generate_preset_xml().
 608       *
 609       * @return array
 610       */
 611      public function generate_preset_xml_provider(): array {
 612          return [
 613              'Generate preset.xml with the default params and empty description' => [
 614                  'params' => [],
 615                  'description' => null,
 616              ],
 617              'Generate preset.xml with a description but the default params' => [
 618                  'params' => [],
 619                  'description' => 'This is a description',
 620              ],
 621              'Generate preset.xml with empty description but changing some params' => [
 622                  'params' => [
 623                      'requiredentries' => 2,
 624                      'approval' => 1,
 625                  ],
 626                  'description' => null,
 627              ],
 628              'Generate preset.xml with a description and changing some params' => [
 629                  'params' => [
 630                      'maxentries' => 5,
 631                      'manageapproved' => 0,
 632                  ],
 633                  'description' => 'This is a description',
 634              ],
 635          ];
 636      }
 637  
 638      /**
 639       * Test for get_file().
 640       *
 641       * @covers ::get_file
 642       */
 643      public function test_get_file() {
 644          $this->resetAfterTest();
 645          $this->setAdminUser();
 646  
 647          // Create a course and a database activity.
 648          $course = $this->getDataGenerator()->create_course();
 649          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 650          $manager = manager::create_from_instance($activity);
 651  
 652          $presetname = 'Saved preset';
 653          // Check file doesn't exist if the preset hasn't been saved yet.
 654          $preset = preset::create_from_instance($manager, $presetname);
 655          $file = preset::get_file($preset->get_path(), 'preset.xml');
 656          $this->assertNull($file);
 657  
 658          // Check file is not empty when there is a saved preset with this name.
 659          $preset->save();
 660          $file = preset::get_file($preset->get_path(), 'preset.xml');
 661          $this->assertNotNull($file);
 662          $this->assertStringContainsString($presetname, $file->get_filepath());
 663          $this->assertEquals('preset.xml', $file->get_filename());
 664  
 665          // Check invalid preset file name doesn't exist.
 666          $file = preset::get_file($preset->get_path(), 'unexistingpreset.xml');
 667          $this->assertNull($file);
 668      }
 669  
 670      /**
 671       * Test for can_manage().
 672       *
 673       * @covers ::can_manage
 674       */
 675      public function test_can_manage() {
 676          $this->resetAfterTest();
 677  
 678          // Create course, database activity and users.
 679          $course = $this->getDataGenerator()->create_course();
 680          $data = $this->getDataGenerator()->create_module('data', ['course' => $course->id]);
 681          $teacher = $this->getDataGenerator()->create_and_enrol($course, 'teacher');
 682          $student = $this->getDataGenerator()->create_and_enrol($course, 'student');
 683          $manager = manager::create_from_instance($data);
 684  
 685          $preset1name = 'Admin preset';
 686          $preset2name = 'Teacher preset';
 687  
 688          // Create a saved preset by admin.
 689          $this->setAdminUser();
 690          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 691          $record = (object) [
 692              'name' => $preset1name,
 693              'description' => 'Testing preset description',
 694          ];
 695          $adminpreset = $plugingenerator->create_preset($data, $record);
 696  
 697          // Create a saved preset by teacher.
 698          $this->setUser($teacher);
 699          $record = (object) [
 700              'name' => $preset2name,
 701              'description' => 'Testing preset description',
 702          ];
 703          $teacherpreset = $plugingenerator->create_preset($data, $record);
 704  
 705          // Plugins can't be deleted.
 706          $pluginpresets = manager::get_available_plugin_presets();
 707          $pluginpreset = reset($pluginpresets);
 708          $this->assertFalse($pluginpreset->can_manage());
 709  
 710          // Admin can delete all saved presets.
 711          $this->setAdminUser();
 712          $this->assertTrue($adminpreset->can_manage());
 713          $this->assertTrue($teacherpreset->can_manage());
 714  
 715          // Teacher can delete their own preset only.
 716          $this->setUser($teacher);
 717          $this->assertFalse($adminpreset->can_manage());
 718          $this->assertTrue($teacherpreset->can_manage());
 719  
 720          // Student can't delete any of the presets.
 721          $this->setUser($student);
 722          $this->assertFalse($adminpreset->can_manage());
 723          $this->assertFalse($teacherpreset->can_manage());
 724      }
 725  
 726      /**
 727       * Test for delete().
 728       *
 729       * @covers ::delete
 730       */
 731      public function test_delete() {
 732          $this->resetAfterTest();
 733  
 734          // Create course, database activity and users.
 735          $course = $this->getDataGenerator()->create_course();
 736          $data = $this->getDataGenerator()->create_module('data', ['course' => $course->id]);
 737          $manager = manager::create_from_instance($data);
 738          $presetname = 'Admin preset';
 739  
 740          // Create a saved preset by admin.
 741          $this->setAdminUser();
 742          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 743          $record = (object) [
 744              'name' => $presetname,
 745              'description' => 'Testing preset description',
 746          ];
 747          $adminpreset = $plugingenerator->create_preset($data, $record);
 748          $initialpresets = $manager->get_available_presets();
 749  
 750          // Plugins can't be deleted.
 751          $pluginpresets = manager::get_available_plugin_presets();
 752          $pluginpreset = reset($pluginpresets);
 753          $result = $pluginpreset->delete();
 754          $currentpluginpresets = manager::get_available_plugin_presets();
 755          $this->assertEquals(count($pluginpresets), count($currentpluginpresets));
 756  
 757          $result = $adminpreset->delete();
 758          $this->assertTrue($result);
 759  
 760          // After deleting the preset, there is no file linked.
 761          $adminpreset = preset::create_from_instance($manager, $presetname);
 762          $this->assertEmpty($adminpreset->storedfile);
 763  
 764          // Check the preset has been deleted.
 765          $currentpresets = $manager->get_available_presets();
 766          $this->assertEquals(count($initialpresets) - 1, count($currentpresets));
 767  
 768          // The behavior of trying to delete a preset twice.
 769          $result = $adminpreset->delete();
 770          $this->assertFalse($result);
 771  
 772          // Check the preset has not been deleted.
 773          $currentpresets = $manager->get_available_presets();
 774          $this->assertEquals(count($initialpresets) - 1, count($currentpresets));
 775  
 776          $emptypreset = preset::create_from_instance($manager, $presetname);
 777          // The behavior of deleting an empty preset.
 778          $result = $emptypreset->delete();
 779          $this->assertFalse($result);
 780  
 781          // Check the preset has not been deleted.
 782          $currentpresets = $manager->get_available_presets();
 783          $this->assertEquals(count($initialpresets) - 1, count($currentpresets));
 784      }
 785  
 786      /**
 787       * Test for the get_fields method.
 788       *
 789       * @covers ::get_fields
 790       */
 791      public function test_get_fields() {
 792          $this->resetAfterTest();
 793          $this->setAdminUser();
 794  
 795          // Create a course and a database activity.
 796          $course = $this->getDataGenerator()->create_course();
 797          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 798          $manager = manager::create_from_instance($activity);
 799  
 800          // Add a field to the activity.
 801          $fieldrecord = new stdClass();
 802          $fieldrecord->name = 'field-1';
 803          $fieldrecord->type = 'text';
 804          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 805          $datagenerator->create_field($fieldrecord, $activity);
 806  
 807          // Create a saved preset.
 808          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 809          $record = (object) [
 810              'name' => 'Testing preset name',
 811              'description' => 'Testing preset description',
 812          ];
 813          $preset = $plugingenerator->create_preset($activity, $record);
 814  
 815          // Check regular fields.
 816          $fields = $preset->get_fields();
 817          $this->assertCount(1, $fields);
 818          $this->assertArrayHasKey('field-1', $fields);
 819          $field = $fields['field-1'];
 820          $this->assertEquals('text', $field->type);
 821          $this->assertEquals('field-1', $field->get_name());
 822          $this->assertEquals(false, $field->get_preview());
 823  
 824          // Check preview fields.
 825          $savedpresets = $manager->get_available_saved_presets();
 826          $preset = reset($savedpresets);
 827          $fields = $preset->get_fields(true);
 828          $this->assertCount(1, $fields);
 829          $this->assertArrayHasKey('field-1', $fields);
 830          $field = $fields['field-1'];
 831          $this->assertEquals('text', $field->type);
 832          $this->assertEquals('field-1', $field->get_name());
 833          $this->assertEquals(true, $field->get_preview());
 834      }
 835  
 836      /**
 837       * Test for the get_sample_entries method.
 838       *
 839       * @covers ::get_sample_entries
 840       */
 841      public function test_get_sample_entries() {
 842          $this->resetAfterTest();
 843  
 844          $user = $this->getDataGenerator()->create_user();
 845          $this->setUser($user);
 846  
 847          // Create a course and a database activity.
 848          $course = $this->getDataGenerator()->create_course();
 849          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 850          $manager = manager::create_from_instance($activity);
 851  
 852          // Add a field to the activity.
 853          $fieldrecord = new stdClass();
 854          $fieldrecord->name = 'field-1';
 855          $fieldrecord->type = 'text';
 856          $datagenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 857          $datagenerator->create_field($fieldrecord, $activity);
 858  
 859          // Create a saved preset.
 860          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 861          $record = (object) [
 862              'name' => 'Testing preset name',
 863              'description' => 'Testing preset description',
 864          ];
 865          $preset = $plugingenerator->create_preset($activity, $record);
 866  
 867          $entries = $preset->get_sample_entries(3);
 868          $this->assertCount(3, $entries);
 869          foreach ($entries as $entry) {
 870              $this->assertEquals($user->id, $entry->userid);
 871              $this->assertEquals($user->email, $entry->email);
 872              $this->assertEquals($user->firstname, $entry->firstname);
 873              $this->assertEquals($user->lastname, $entry->lastname);
 874              $this->assertEquals($activity->id, $entry->dataid);
 875              $this->assertEquals(0, $entry->groupid);
 876              $this->assertEquals(1, $entry->approved);
 877          }
 878      }
 879  
 880      /**
 881       * Test for the get_template_content method.
 882       *
 883       * @covers ::get_template_content
 884       */
 885      public function test_get_template_content() {
 886          $this->resetAfterTest();
 887  
 888          $user = $this->getDataGenerator()->create_user();
 889          $this->setUser($user);
 890          $course = $this->getDataGenerator()->create_course();
 891  
 892          // Module data with templates.
 893          $templates = [
 894              'singletemplate' => 'Single template content',
 895              'listtemplate' => 'List template content',
 896              'listtemplateheader' => 'List template content header',
 897              'listtemplatefooter' => 'List template content footer',
 898              'addtemplate' => 'Add template content',
 899              'rsstemplate' => 'RSS template content',
 900              'rsstitletemplate' => 'RSS title template content',
 901              'csstemplate' => 'CSS template content',
 902              'jstemplate' => 'JS template content',
 903              'asearchtemplate' => 'Advanced search template content',
 904          ];
 905          $params = array_merge(['course' => $course], $templates);
 906  
 907          // Create a database activity.
 908          $activity = $this->getDataGenerator()->create_module(manager::MODULE, $params);
 909          $manager = manager::create_from_instance($activity);
 910  
 911          // Create a saved preset.
 912          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 913          $record = (object) [
 914              'name' => 'Testing preset name',
 915              'description' => 'Testing preset description',
 916          ];
 917          $preset = $plugingenerator->create_preset($activity, $record);
 918  
 919          // Test user preset templates.
 920          foreach ($templates as $templatename => $templatecontent) {
 921              $content = $preset->get_template_content($templatename);
 922              $this->assertEquals($templatecontent, $content);
 923          }
 924  
 925          // Test plugin preset content.
 926          $pluginname = 'imagegallery';
 927          $preset = preset::create_from_plugin($manager, $pluginname);
 928          foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) {
 929              // Get real file contents.
 930              $path = $manager->path . '/preset/' . $pluginname . '/' . $templatefile;
 931              $templatecontent = file_get_contents($path);
 932              $content = $preset->get_template_content($templatename);
 933              $this->assertEquals($templatecontent, $content);
 934          }
 935      }
 936  
 937      /**
 938       * Test for the get_fullname method.
 939       *
 940       * @covers ::get_fullname
 941       */
 942      public function test_get_fullname() {
 943          $this->resetAfterTest();
 944  
 945          $user = $this->getDataGenerator()->create_user();
 946          $this->setUser($user);
 947          $course = $this->getDataGenerator()->create_course();
 948  
 949          // Create a database activity.
 950          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 951          $manager = manager::create_from_instance($activity);
 952  
 953          // Create a saved preset.
 954          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 955          $record = (object) [
 956              'name' => 'Testing preset name',
 957              'description' => 'Testing preset description',
 958          ];
 959          $preset = $plugingenerator->create_preset($activity, $record);
 960  
 961          // Test user preset templates.
 962          $this->assertEquals("{$user->id}/Testing preset name", $preset->get_fullname());
 963  
 964          // Test plugin preset content.
 965          $pluginname = 'imagegallery';
 966          $preset = preset::create_from_plugin($manager, $pluginname);
 967          $this->assertEquals("0/imagegallery", $preset->get_fullname());
 968      }
 969  }