Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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