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 310 and 401]

   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  declare(strict_types=1);
  18  
  19  namespace core\content\export\exportable_items;
  20  
  21  use advanced_testcase;
  22  use context;
  23  use context_system;
  24  use core\content\export\zipwriter;
  25  use core\content\export\exported_item;
  26  use moodle_url;
  27  use stdClass;
  28  
  29  /**
  30   * Unit tests for the `exportable_filearea` export item class.
  31   *
  32   * @package     core
  33   * @category    test
  34   * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
  35   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   * @covers      \core\content\exportable_items\exportable_filearea
  37   */
  38  class exportable_filearea_test extends advanced_testcase {
  39  
  40      /**
  41       * Ensure that the the exportable_filearea does not fetch files when none exist.
  42       */
  43      public function test_no_files(): void {
  44          $exportable = new exportable_filearea(
  45              context_system::instance(),
  46              'fake',
  47              'Some fake filearea',
  48              'filearea',
  49              1
  50          );
  51  
  52          $this->assertInstanceOf(exportable_filearea::class, $exportable);
  53      }
  54  
  55      /**
  56       * Ensure that the exportable_filearea returns all stored_file items for only the specified itemid, but those which
  57       * are not included in the archive receive a pluginfile URL.
  58       */
  59      public function test_specified_itemid_excluded_from_zip(): void {
  60          $this->resetAfterTest(true);
  61  
  62          // Setup for test.
  63          $user = $this->getDataGenerator()->create_user();
  64          $context = context_system::instance();
  65          $component = 'fake';
  66          $filearea = 'myfirstfilearea';
  67  
  68          $files1 = $this->create_files(context_system::instance(), $component, $filearea, 1);
  69          $files2 = $this->create_files(context_system::instance(), $component, $filearea, 2);
  70          $files3 = $this->create_files(context_system::instance(), $component, $filearea, 3);
  71          $otherfiles2 = $this->create_files(context_system::instance(), $component, "other{$filearea}", 2);
  72  
  73          $exportable = new exportable_filearea(
  74              $context,
  75              $component,
  76              'Some filearea description',
  77              $filearea,
  78              2
  79          );
  80  
  81          // There is only one exportable.
  82          $this->assertInstanceOf(exportable_filearea::class, $exportable);
  83  
  84          $file2 = reset($files2);
  85          $item = $this->assert_exportable_matches_file($component, $user, $context, $filearea, '', $files2, false, $exportable);
  86          $this->assertCount(count($files2), $item->get_all_files());
  87          $comparisonurl = new moodle_url('/tokenpluginfile.php/');
  88          foreach ($item->get_all_files() as $url) {
  89              $this->assertStringStartsWith($comparisonurl->out(false), $url->filepath);
  90          }
  91      }
  92  
  93      /**
  94       * Ensure that the exportable_filearea returns all stored_file items for only the specified itemid.
  95       */
  96      public function test_specified_itemid(): void {
  97          $this->resetAfterTest(true);
  98  
  99          // Setup for test.
 100          $user = $this->getDataGenerator()->create_user();
 101          $context = context_system::instance();
 102          $component = 'fake';
 103          $filearea = 'myfirstfilearea';
 104  
 105          $files1 = $this->create_files(context_system::instance(), $component, $filearea, 1);
 106          $files2 = $this->create_files(context_system::instance(), $component, $filearea, 2);
 107          $files3 = $this->create_files(context_system::instance(), $component, $filearea, 3);
 108          $otherfiles2 = $this->create_files(context_system::instance(), $component, "other{$filearea}", 2);
 109  
 110          $exportable = new exportable_filearea(
 111              $context,
 112              $component,
 113              'Some filearea description',
 114              $filearea,
 115              2
 116          );
 117  
 118          // There is only one exportable.
 119          $this->assertInstanceOf(exportable_filearea::class, $exportable);
 120  
 121          $file2 = reset($files2);
 122          $item = $this->assert_exportable_matches_file($component, $user, $context, $filearea, '', $files2, true, $exportable);
 123          $this->assertCount(count($files2), $item->get_all_files());
 124      }
 125  
 126      /**
 127       * Ensure that the exportable_filearea returns all stored_files into the correct file location.
 128       */
 129      public function test_in_subdir(): void {
 130          $this->resetAfterTest(true);
 131  
 132          // Setup for test.
 133          $user = $this->getDataGenerator()->create_user();
 134          $context = context_system::instance();
 135          $component = 'fake';
 136          $filearea = 'myfirstfilearea';
 137          $subdir = 'a/path/to/my/subdir';
 138  
 139          $files1 = $this->create_files(context_system::instance(), $component, $filearea, 1);
 140          $files2 = $this->create_files(context_system::instance(), $component, $filearea, 2);
 141          $files3 = $this->create_files(context_system::instance(), $component, $filearea, 3);
 142  
 143          $exportable = new exportable_filearea(
 144              $context,
 145              $component,
 146              'Some filearea description',
 147              $filearea,
 148              2,
 149              2,
 150              $subdir
 151          );
 152  
 153          // There is only one exportable.
 154          $this->assertInstanceOf(exportable_filearea::class, $exportable);
 155  
 156          $item = $this->assert_exportable_matches_file($component, $user, $context, $filearea, $subdir, $files2, true, $exportable);
 157          $this->assertCount(count($files2), $item->get_all_files());
 158      }
 159  
 160      /**
 161       * Create files for use in testing.
 162       *
 163       * @param   context $context
 164       * @param   string $component
 165       * @param   string $filearea
 166       * @param   int $itemid
 167       * @param   int $count
 168       * @return  filearea[]
 169       */
 170      protected function create_files(context $context, string $component, string $filearea, int $itemid, int $count = 1): array {
 171          $fs = get_file_storage();
 172  
 173          $files = [];
 174          for ($i = 0; $i < $count; $i++) {
 175  
 176              $filepath = '/';
 177              for ($j = 0; $j < $i; $j++) {
 178                  $filepath .= "{$j}/";
 179              }
 180  
 181              $files[] = $fs->create_file_from_string(
 182                  (object) [
 183                      'contextid' => $context->id,
 184                      'component' => $component,
 185                      'filearea' => $filearea,
 186                      'filepath' => $filepath,
 187                      'filename' => "file.txt",
 188                      'itemid' => $itemid,
 189                  ],
 190                  "File content: {$i}"
 191              );
 192          }
 193  
 194          return $files;
 195      }
 196  
 197      /**
 198       * Assert that the supplied expotable matches the supplied file.
 199       *
 200       * @param   string $component
 201       * @param   stdClass $user
 202       * @param   context $context
 203       * @param   string $filearea
 204       * @param   string $subdir
 205       * @param   stored_file[] $expectedfiles
 206       * @param   bool $addfilestozip Whether to allow files to be added to the archive
 207       * @param   exportable_filearea $exportable
 208       * @return  exported_item
 209       */
 210      protected function assert_exportable_matches_file(
 211          string $component,
 212          stdClass $user,
 213          context $context,
 214          string $filearea,
 215          string $subdir,
 216          array $expectedfiles,
 217          bool $addfilestozip,
 218          exportable_filearea $exportable
 219      ): exported_item {
 220          $archive = $this->getMockBuilder(zipwriter::class)
 221              ->setConstructorArgs([$this->getMockBuilder(\ZipStream\ZipStream::class)->getmock()])
 222              ->onlyMethods([
 223                  'add_file_from_stored_file',
 224                  'is_file_in_archive',
 225              ])
 226              ->getMock();
 227  
 228          $archive->expects($this->any())
 229              ->method('is_file_in_archive')
 230              ->willReturn($addfilestozip);
 231  
 232          $storedfileargs = [];
 233          foreach ($expectedfiles as $file) {
 234              $filepathinzip = $subdir . '/' . $file->get_filearea() . '/' . $file->get_filepath() . $file->get_filename();
 235              $filepathinzip = ltrim(preg_replace('#/+#', '/', $filepathinzip), '/');
 236              $storedfileargs[] = [
 237                  $this->equalTo($context),
 238                  $this->equalTo($filepathinzip),
 239                  $this->equalTo($file),
 240              ];
 241          }
 242  
 243          $archive->expects($this->exactly(count($expectedfiles)))
 244              ->method('add_file_from_stored_file')
 245              ->withConsecutive(...$storedfileargs);
 246  
 247          return $exportable->add_to_archive($archive);
 248      }
 249  }