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 mod_data\local\importer\preset_existing_importer;
  20  use mod_data\local\importer\preset_importer;
  21  
  22  /**
  23   * Preset importer tests class for mod_data.
  24   *
  25   * @package    mod_data
  26   * @category   test
  27   * @copyright  2022 Amaia Anabitarte <amaia@moodle.com>
  28   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  29   * @coversDefaultClass \mod_data\local\importer\preset_importer
  30   */
  31  class preset_importer_test extends \advanced_testcase {
  32  
  33      /**
  34       * Data provider for build providers for test_needs_mapping and test_set_affected_fields.
  35       *
  36       * @return array[]
  37       */
  38      public function preset_importer_provider(): array {
  39          // Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
  40  
  41          $titlefield = new \stdClass();
  42          $titlefield->name = 'title';
  43          $titlefield->type = 'text';
  44  
  45          $descfield = new \stdClass();
  46          $descfield->name = 'description';
  47          $descfield->type = 'textarea';
  48  
  49          $imagefield = new \stdClass();
  50          $imagefield->name = 'image';
  51          $imagefield->type = 'picture';
  52  
  53          $difffield = new \stdClass();
  54          $difffield->name = 'title';
  55          $difffield->type = 'textarea';
  56  
  57          $newfield = new \stdClass();
  58          $newfield->name = 'number';
  59          $newfield->type = 'number';
  60  
  61          return [
  62              'Empty database / Empty importer' => [
  63                  'currentfields' => [],
  64                  'newfields' => [],
  65                  'pluginname' => '',
  66              ],
  67              'Empty database / Importer with fields' => [
  68                  'currentfields' => [],
  69                  'newfields' => [$titlefield, $descfield, $imagefield],
  70                  'pluginname' => 'imagegallery',
  71              ],
  72              'Database with fields / Empty importer' => [
  73                  'currentfields' => [$titlefield, $descfield, $imagefield],
  74                  'newfields' => [],
  75                  'pluginname' => '',
  76              ],
  77              'Same fields' => [
  78                  'currentfields' => [$titlefield, $descfield, $imagefield],
  79                  'newfields' => [$titlefield, $descfield, $imagefield],
  80                  'pluginname' => 'imagegallery',
  81              ],
  82              'Fields to create' => [
  83                  'currentfields' => [$titlefield, $descfield],
  84                  'newfields' => [$titlefield, $descfield, $imagefield],
  85                  'pluginname' => 'imagegallery',
  86              ],
  87              'Fields to remove' => [
  88                  'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
  89                  'newfields' => [$titlefield, $descfield, $imagefield],
  90                  'pluginname' => 'imagegallery',
  91              ],
  92              'Fields to update' => [
  93                  'currentfields' => [$difffield, $descfield, $imagefield],
  94                  'newfields' => [$titlefield, $descfield, $imagefield],
  95                  'pluginname' => 'imagegallery',
  96              ],
  97              'Fields to create, remove and update' => [
  98                  'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
  99                  'newfields' => [$titlefield, $descfield, $newfield],
 100                  'pluginname' => '',
 101              ],
 102          ];
 103      }
 104  
 105      /**
 106       * Data provider for needs_mapping().
 107       *
 108       * @return array[]
 109       */
 110      public function needs_mapping_provider(): array {
 111          $basedprovider = $this->preset_importer_provider();
 112  
 113          $basedprovider['Empty database / Empty importer']['needsmapping'] = false;
 114          $basedprovider['Empty database / Importer with fields']['needsmapping'] = false;
 115          $basedprovider['Database with fields / Empty importer']['needsmapping'] = true;
 116          $basedprovider['Same fields']['needsmapping'] = false;
 117          $basedprovider['Fields to create']['needsmapping'] = true;
 118          $basedprovider['Fields to remove']['needsmapping'] = true;
 119          $basedprovider['Fields to update']['needsmapping'] = true;
 120          $basedprovider['Fields to create, remove and update']['needsmapping'] = true;
 121  
 122          return $basedprovider;
 123      }
 124  
 125      /**
 126       * Test for needs_mapping method.
 127       *
 128       * @dataProvider needs_mapping_provider
 129       * @covers ::needs_mapping
 130       *
 131       * @param array $currentfields Fields of the current activity.
 132       * @param array $newfields Fields to be imported.
 133       * @param string $pluginname The plugin preset to be imported.
 134       * @param bool $expectedresult Expected exception.
 135       */
 136      public function test_needs_mapping(
 137          array $currentfields,
 138          array $newfields,
 139          string $pluginname,
 140          bool $expectedresult
 141      ) {
 142  
 143          global $USER;
 144  
 145          $this->resetAfterTest();
 146          $this->setAdminUser();
 147          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 148  
 149          // Create a course and a database activity.
 150          $course = $this->getDataGenerator()->create_course();
 151          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 152          // Add current fields to the activity.
 153          foreach ($currentfields as $field) {
 154              $plugingenerator->create_field($field, $activity);
 155          }
 156          $manager = manager::create_from_instance($activity);
 157  
 158          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 159          // Add current fields to the activity.
 160          foreach ($newfields as $field) {
 161              $plugingenerator->create_field($field, $presetactivity);
 162          }
 163  
 164          $record = (object) [
 165              'name' => 'Testing preset name',
 166              'description' => 'Testing preset description',
 167          ];
 168          $saved = $plugingenerator->create_preset($presetactivity, $record);
 169          $savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
 170          $this->assertEquals($savedimporter->needs_mapping(), $expectedresult);
 171  
 172          // Create presets and importers.
 173          if ($pluginname) {
 174              $plugin = preset::create_from_plugin(null, $pluginname);
 175              $pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
 176              $this->assertEquals($pluginimporter->needs_mapping(), $expectedresult);
 177          }
 178      }
 179  
 180      /**
 181       * Data provider for test_set_affected_fields().
 182       *
 183       * @return array[]
 184       */
 185      public function set_affected_provider(): array {
 186          $basedprovider = $this->preset_importer_provider();
 187  
 188          $basedprovider['Empty database / Empty importer']['fieldstocreate'] = 0;
 189          $basedprovider['Empty database / Empty importer']['fieldstoremove'] = 0;
 190          $basedprovider['Empty database / Empty importer']['fieldstoupdate'] = 0;
 191  
 192          $basedprovider['Empty database / Importer with fields']['fieldstocreate'] = 3;
 193          $basedprovider['Empty database / Importer with fields']['fieldstoremove'] = 0;
 194          $basedprovider['Empty database / Importer with fields']['fieldstoupdate'] = 0;
 195  
 196          $basedprovider['Database with fields / Empty importer']['fieldstocreate'] = 0;
 197          $basedprovider['Database with fields / Empty importer']['fieldstoremove'] = 3;
 198          $basedprovider['Database with fields / Empty importer']['fieldstoupdate'] = 0;
 199  
 200          $basedprovider['Same fields']['fieldstocreate'] = 0;
 201          $basedprovider['Same fields']['fieldstoremove'] = 0;
 202          $basedprovider['Same fields']['fieldstoupdate'] = 3;
 203  
 204          $basedprovider['Fields to create']['fieldstocreate'] = 1;
 205          $basedprovider['Fields to create']['fieldstoremove'] = 0;
 206          $basedprovider['Fields to create']['fieldstoupdate'] = 2;
 207  
 208          $basedprovider['Fields to remove']['fieldstocreate'] = 0;
 209          $basedprovider['Fields to remove']['fieldstoremove'] = 1;
 210          $basedprovider['Fields to remove']['fieldstoupdate'] = 3;
 211  
 212          $basedprovider['Fields to update']['fieldstocreate'] = 1;
 213          $basedprovider['Fields to update']['fieldstoremove'] = 1;
 214          $basedprovider['Fields to update']['fieldstoupdate'] = 2;
 215  
 216          $basedprovider['Fields to create, remove and update']['fieldstocreate'] = 1;
 217          $basedprovider['Fields to create, remove and update']['fieldstoremove'] = 2;
 218          $basedprovider['Fields to create, remove and update']['fieldstoupdate'] = 2;
 219  
 220          return $basedprovider;
 221      }
 222  
 223      /**
 224       * Test for set_affected_fields method.
 225       *
 226       * @dataProvider set_affected_provider
 227       * @covers ::set_affected_fields
 228       *
 229       * @param array $currentfields Fields of the current activity.
 230       * @param array $newfields Fields to be imported.
 231       * @param string $pluginname The plugin preset to be imported.
 232       * @param int $fieldstocreate Expected number of fields on $fieldstocreate.
 233       * @param int $fieldstoremove Expected number of fields on $fieldstoremove.
 234       * @param int $fieldstoupdate Expected number of fields on $fieldstoupdate.
 235       */
 236      public function test_set_affected_fields(
 237          array $currentfields,
 238          array $newfields,
 239          string $pluginname,
 240          int $fieldstocreate,
 241          int $fieldstoremove,
 242          int $fieldstoupdate
 243      ) {
 244          global $USER;
 245  
 246          $this->resetAfterTest();
 247          $this->setAdminUser();
 248          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 249  
 250          // Create a course and a database activity.
 251          $course = $this->getDataGenerator()->create_course();
 252          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 253          // Add current fields to the activity.
 254          foreach ($currentfields as $field) {
 255              $plugingenerator->create_field($field, $activity);
 256          }
 257          $manager = manager::create_from_instance($activity);
 258  
 259          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 260          // Add current fields to the activity.
 261          foreach ($newfields as $field) {
 262              $plugingenerator->create_field($field, $presetactivity);
 263          }
 264  
 265          $record = (object) [
 266              'name' => 'Testing preset name',
 267              'description' => 'Testing preset description',
 268          ];
 269          $saved = $plugingenerator->create_preset($presetactivity, $record);
 270          $savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
 271          $this->assertEquals(count($savedimporter->fieldstoremove), $fieldstoremove);
 272          $this->assertEquals(count($savedimporter->fieldstocreate), $fieldstocreate);
 273          $this->assertEquals(count($savedimporter->fieldstoupdate), $fieldstoupdate);
 274  
 275          // Create presets and importers.
 276          if ($pluginname) {
 277              $plugin = preset::create_from_plugin(null, $pluginname);
 278              $pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
 279              $this->assertEquals(count($pluginimporter->fieldstoremove), $fieldstoremove);
 280              $this->assertEquals(count($pluginimporter->fieldstocreate), $fieldstocreate);
 281              $this->assertEquals(count($pluginimporter->fieldstoupdate), $fieldstoupdate);
 282          }
 283      }
 284  
 285      /**
 286       * Test for get_mapping_information method.
 287       *
 288       * @dataProvider set_affected_provider
 289       * @covers ::get_mapping_information
 290       *
 291       * @param array $currentfields Fields of the current activity.
 292       * @param array $newfields Fields to be imported.
 293       * @param string $pluginname The plugin preset to be imported.
 294       * @param int $fieldstocreate Expected number of fields on $fieldstocreate.
 295       * @param int $fieldstoremove Expected number of fields on $fieldstoremove.
 296       * @param int $fieldstoupdate Expected number of fields on $fieldstoupdate.
 297       */
 298      public function test_get_mapping_information(
 299          array $currentfields,
 300          array $newfields,
 301          string $pluginname,
 302          int $fieldstocreate,
 303          int $fieldstoremove,
 304          int $fieldstoupdate
 305      ) {
 306          global $USER;
 307  
 308          $this->resetAfterTest();
 309          $this->setAdminUser();
 310          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 311  
 312          // Create a course and a database activity.
 313          $course = $this->getDataGenerator()->create_course();
 314          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 315          // Add current fields to the activity.
 316          foreach ($currentfields as $field) {
 317              $plugingenerator->create_field($field, $activity);
 318          }
 319          $manager = manager::create_from_instance($activity);
 320  
 321          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 322          // Add current fields to the activity.
 323          foreach ($newfields as $field) {
 324              $plugingenerator->create_field($field, $presetactivity);
 325          }
 326  
 327          $record = (object) [
 328              'name' => 'Testing preset name',
 329              'description' => 'Testing preset description',
 330          ];
 331          $saved = $plugingenerator->create_preset($presetactivity, $record);
 332          $savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
 333          $information = $savedimporter->get_mapping_information();
 334          $this->assertEquals($savedimporter->needs_mapping(), $information['needsmapping']);
 335          $this->assertEquals(count($savedimporter->fieldstoremove), $fieldstoremove);
 336          $this->assertEquals(count($savedimporter->fieldstocreate), $fieldstocreate);
 337          $this->assertEquals(count($savedimporter->fieldstoupdate), $fieldstoupdate);
 338  
 339          // Create presets and importers.
 340          if ($pluginname) {
 341              $plugin = preset::create_from_plugin(null, $pluginname);
 342              $pluginimporter = new preset_existing_importer($manager, '/' . $pluginname);
 343              $information = $pluginimporter->get_mapping_information();
 344              $this->assertEquals($pluginimporter->needs_mapping(), $information['needsmapping']);
 345              $this->assertEquals(count($pluginimporter->fieldstoremove), $fieldstoremove);
 346              $this->assertEquals(count($pluginimporter->fieldstocreate), $fieldstocreate);
 347              $this->assertEquals(count($pluginimporter->fieldstoupdate), $fieldstoupdate);
 348          }
 349      }
 350  
 351      /**
 352       * Data provider for get_field_names().
 353       *
 354       * @return array[]
 355       */
 356      public function get_field_names_provider(): array {
 357          return [
 358              'Empty list' => [
 359                  'fields' => [],
 360                  'expected' => '',
 361              ],
 362              'List with one field' => [
 363                  'fields' => ['fieldname' => 'text'],
 364                  'expected' => 'fieldname',
 365              ],
 366              'List of fields with same type' => [
 367                  'fields' => ['textfield' => 'text', 'other' => 'text'],
 368                  'expected' => 'textfield, other',
 369              ],
 370              'List of fields with different type' => [
 371                  'fields' => ['textfield' => 'text', 'number' => 'number'],
 372                  'expected' => 'textfield, number',
 373              ],
 374          ];
 375      }
 376  
 377      /**
 378       * Test for get_field_names method.
 379       *
 380       * @dataProvider get_field_names_provider
 381       * @covers ::get_field_names
 382       *
 383       * @param array $fields List of fields to get the names from.
 384       * @param string $expected The list of field names expected.
 385       */
 386      public function test_get_field_names(array $fields, string $expected) {
 387          global $USER;
 388  
 389          $this->resetAfterTest();
 390          $this->setAdminUser();
 391          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 392  
 393          // Create a course and a database activity.
 394          $course = $this->getDataGenerator()->create_course();
 395          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 396          foreach ($fields as $fieldname => $fieldtype) {
 397              $newfield = new \stdClass();
 398              $newfield->name = $fieldname;
 399              $newfield->type = $fieldtype;
 400  
 401              $createdfield = $plugingenerator->create_field($newfield, $presetactivity);
 402          }
 403          $manager = manager::create_from_instance($presetactivity);
 404  
 405          $record = (object) [
 406              'name' => 'Testing preset name',
 407              'description' => 'Testing preset description',
 408          ];
 409          $saved = $plugingenerator->create_preset($presetactivity, $record);
 410          $savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
 411          $this->assertEquals($expected, $savedimporter->get_field_names($manager->get_field_records()));
 412      }
 413  
 414      /**
 415       * Test for create_from_plugin_or_directory creation static method.
 416       *
 417       * @covers ::create_from_plugin_or_directory
 418       *
 419       */
 420      public function test_create_from_plugin_or_directory() {
 421  
 422          global $USER;
 423  
 424          $this->resetAfterTest();
 425          $this->setAdminUser();
 426          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 427  
 428          // Create a course and a database activity.
 429          $course = $this->getDataGenerator()->create_course();
 430          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 431          $manager = manager::create_from_instance($activity);
 432  
 433          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 434  
 435          $record = (object) [
 436              'name' => 'Testing preset name',
 437              'description' => 'Testing preset description',
 438          ];
 439          $saved = $plugingenerator->create_preset($presetactivity, $record);
 440  
 441          // A plugin preset returns an instance of preset_existing_importer.
 442          $preset = preset_importer::create_from_plugin_or_directory($manager, '/imagegallery');
 443          $this->assertInstanceOf('\mod_data\local\importer\preset_existing_importer', $preset);
 444  
 445          // A saved preset returns an instance of preset_existing_importer.
 446          $preset = preset_importer::create_from_plugin_or_directory($manager, $USER->id . '/Testing preset name');
 447          $this->assertInstanceOf('\mod_data\local\importer\preset_existing_importer', $preset);
 448  
 449          // An empty preset name throws an exception.
 450          $this->expectException('moodle_exception');
 451          try {
 452              preset_importer::create_from_plugin_or_directory($manager, '');
 453          } finally {
 454              // A non-existing preset name throws an exception.
 455              $this->expectException('moodle_exception');
 456              preset_importer::create_from_plugin_or_directory($manager, $USER->id . '/Non-existing');
 457          }
 458      }
 459  }