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] [Versions 39 and 310]

   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  /**
  19   * PHPUnit tests for conversion API.
  20   *
  21   * @package    core_files
  22   * @copyright  2017 Andrew nicols <andrew@nicols.co.uk>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  global $CFG;
  28  
  29  use core_files\conversion;
  30  
  31  /**
  32   * PHPUnit tests for conversion persistent.
  33   *
  34   * @package    core_files
  35   * @copyright  2017 Andrew nicols <andrew@nicols.co.uk>
  36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  37   */
  38  class core_files_conversion_testcase extends advanced_testcase {
  39  
  40      /**
  41       * Helper to create a stored file object with the given supplied content.
  42       *
  43       * @param   string $filecontent The content of the mocked file
  44       * @param   string $filename The file name to use in the stored_file
  45       * @param   string $filerecord Any overrides to the filerecord
  46       * @return  stored_file
  47       */
  48      protected function create_stored_file($filecontent = 'content', $filename = 'testfile.txt', $filerecord = []) {
  49          $filerecord = array_merge([
  50                  'contextid' => context_system::instance()->id,
  51                  'component' => 'core',
  52                  'filearea'  => 'unittest',
  53                  'itemid'    => 0,
  54                  'filepath'  => '/',
  55                  'filename'  => $filename,
  56              ], $filerecord);
  57  
  58          $fs = get_file_storage();
  59          $file = $fs->create_file_from_string($filerecord, $filecontent);
  60  
  61          return $file;
  62      }
  63  
  64      /**
  65       * Ensure that get_conversions_for_file returns an existing conversion
  66       * record with matching sourcefileid and targetformat.
  67       */
  68      public function test_get_conversions_for_file_existing_conversion_incomplete() {
  69          $this->resetAfterTest();
  70  
  71          $sourcefile = $this->create_stored_file();
  72  
  73          $existing = new conversion(0, (object) [
  74                  'sourcefileid' => $sourcefile->get_id(),
  75                  'targetformat' => 'pdf',
  76              ]);
  77          $existing->create();
  78  
  79          $conversions = conversion::get_conversions_for_file($sourcefile, 'pdf');
  80  
  81          $this->assertCount(1, $conversions);
  82  
  83          $conversion = array_shift($conversions);
  84          $conversionfile = $conversion->get_sourcefile();
  85  
  86          $this->assertEquals($sourcefile->get_id(), $conversionfile->get_id());
  87          $this->assertFalse($conversion->get_destfile());
  88      }
  89  
  90      /**
  91       * Ensure that get_conversions_for_file returns an existing conversion
  92       * record with matching sourcefileid and targetformat when a second
  93       * conversion to a different format exists.
  94       */
  95      public function test_get_conversions_for_file_existing_conversion_multiple_formats_incomplete() {
  96          $this->resetAfterTest();
  97  
  98          $sourcefile = $this->create_stored_file();
  99  
 100          $existing = new conversion(0, (object) [
 101                  'sourcefileid' => $sourcefile->get_id(),
 102                  'targetformat' => 'pdf',
 103              ]);
 104          $existing->create();
 105  
 106          $second = new conversion(0, (object) [
 107                  'sourcefileid' => $sourcefile->get_id(),
 108                  'targetformat' => 'doc',
 109              ]);
 110          $second->create();
 111  
 112          $conversions = conversion::get_conversions_for_file($sourcefile, 'pdf');
 113  
 114          $this->assertCount(1, $conversions);
 115  
 116          $conversion = array_shift($conversions);
 117          $conversionfile = $conversion->get_sourcefile();
 118  
 119          $this->assertEquals($sourcefile->get_id(), $conversionfile->get_id());
 120          $this->assertFalse($conversion->get_destfile());
 121      }
 122  
 123      /**
 124       * Ensure that get_conversions_for_file returns an existing conversion
 125       * record with matching sourcefileid and targetformat.
 126       */
 127      public function test_get_conversions_for_file_existing_conversion_complete() {
 128          $this->resetAfterTest();
 129  
 130          $sourcefile = $this->create_stored_file();
 131          $destfile = $this->create_stored_file(
 132              'example content',
 133              $sourcefile->get_contenthash(),
 134              [
 135                  'component' => 'core',
 136                  'filearea' => 'documentconversion',
 137                  'filepath' => '/pdf/',
 138              ]);
 139  
 140          $existing = new conversion(0, (object) [
 141                  'sourcefileid' => $sourcefile->get_id(),
 142                  'targetformat' => 'pdf',
 143                  'destfileid' => $destfile->get_id(),
 144              ]);
 145          $existing->create();
 146  
 147          $conversions = conversion::get_conversions_for_file($sourcefile, 'pdf');
 148  
 149          // Only one file should be returned.
 150          $this->assertCount(1, $conversions);
 151  
 152          $conversion = array_shift($conversions);
 153  
 154          $this->assertEquals($sourcefile->get_id(), $conversion->get_sourcefile()->get_id());
 155          $this->assertEquals($destfile->get_id(), $conversion->get_destfile()->get_id());
 156      }
 157  
 158      /**
 159       * Ensure that get_conversions_for_file returns an existing conversion
 160       * record with matching sourcefileid and targetformat.
 161       */
 162      public function test_get_conversions_for_file_existing_conversion_multiple_formats_complete() {
 163          $this->resetAfterTest();
 164  
 165          $sourcefile = $this->create_stored_file();
 166          $destfile = $this->create_stored_file(
 167              'example content',
 168              $sourcefile->get_contenthash(),
 169              [
 170                  'component' => 'core',
 171                  'filearea' => 'documentconversion',
 172                  'filepath' => '/pdf/',
 173              ]);
 174  
 175          $existing = new conversion(0, (object) [
 176                  'sourcefileid' => $sourcefile->get_id(),
 177                  'targetformat' => 'pdf',
 178                  'destfileid' => $destfile->get_id(),
 179              ]);
 180          $existing->create();
 181  
 182          $second = new conversion(0, (object) [
 183                  'sourcefileid' => $sourcefile->get_id(),
 184                  'targetformat' => 'doc',
 185              ]);
 186          $second->create();
 187  
 188          $conversions = conversion::get_conversions_for_file($sourcefile, 'pdf');
 189  
 190          // Only one file should be returned.
 191          $this->assertCount(1, $conversions);
 192  
 193          $conversion = array_shift($conversions);
 194  
 195          $this->assertEquals($sourcefile->get_id(), $conversion->get_sourcefile()->get_id());
 196          $this->assertEquals($destfile->get_id(), $conversion->get_destfile()->get_id());
 197      }
 198  
 199      /**
 200       * Ensure that get_conversions_for_file returns an existing conversion
 201       * record does not exist, but the file has previously been converted.
 202       */
 203      public function test_get_conversions_for_file_existing_target() {
 204          $this->resetAfterTest();
 205  
 206          $sourcefile = $this->create_stored_file();
 207          $destfile = $this->create_stored_file(
 208              'example content',
 209              $sourcefile->get_contenthash(),
 210              [
 211                  'component' => 'core',
 212                  'filearea' => 'documentconversion',
 213                  'filepath' => '/pdf/',
 214              ]);
 215  
 216          $conversions = conversion::get_conversions_for_file($sourcefile, 'pdf');
 217  
 218          $this->assertCount(1, $conversions);
 219  
 220          $conversion = array_shift($conversions);
 221          $conversionsource = $conversion->get_sourcefile();
 222          $this->assertEquals($sourcefile->get_id(), $conversionsource->get_id());
 223          $conversiondest = $conversion->get_destfile();
 224          $this->assertEquals($destfile->get_id(), $conversiondest->get_id());
 225      }
 226  
 227      /**
 228       * Ensure that set_sourcefile sets the correct fileid.
 229       */
 230      public function test_set_sourcefile() {
 231          $this->resetAfterTest();
 232  
 233          $sourcefile = $this->create_stored_file();
 234          $conversion = new conversion(0, (object) []);
 235  
 236          $conversion->set_sourcefile($sourcefile);
 237  
 238          $this->assertEquals($sourcefile->get_id(), $conversion->get('sourcefileid'));
 239          $this->assertNull($conversion->get('destfileid'));
 240      }
 241  
 242      /**
 243       * Ensure that store_destfile_from_path stores the file as expected.
 244       */
 245      public function test_store_destfile_from_path() {
 246          $this->resetAfterTest();
 247  
 248          $sourcefile = $this->create_stored_file();
 249          $conversion = new conversion(0, (object) [
 250              'sourcefileid' => $sourcefile->get_id(),
 251              'targetformat' => 'pdf',
 252          ]);
 253  
 254          $fixture = __FILE__;
 255          $conversion->store_destfile_from_path($fixture);
 256  
 257          $destfile = $conversion->get_destfile();
 258          $this->assertEquals(file_get_contents($fixture), $destfile->get_content());
 259      }
 260  
 261      /**
 262       * Ensure that store_destfile_from_path stores the file as expected.
 263       */
 264      public function test_store_destfile_from_path_delete_existing() {
 265          $this->resetAfterTest();
 266  
 267          $sourcefile = $this->create_stored_file();
 268          $conversion = new conversion(0, (object) [
 269              'sourcefileid' => $sourcefile->get_id(),
 270              'targetformat' => 'pdf',
 271          ]);
 272  
 273          $record = [
 274              'contextid' => \context_system::instance()->id,
 275              'component' => 'core',
 276              'filearea'  => 'documentconversion',
 277              'itemid'    => 0,
 278              'filepath'  => '/pdf/',
 279          ];
 280          $existingfile = $this->create_stored_file('foo', $sourcefile->get_contenthash(), $record);
 281  
 282          $fixture = __FILE__;
 283          $conversion->store_destfile_from_path($fixture);
 284  
 285          $destfile = $conversion->get_destfile();
 286          $this->assertEquals(file_get_contents($fixture), $destfile->get_content());
 287      }
 288  
 289      /**
 290       * Ensure that store_destfile_from_path stores the file as expected.
 291       */
 292      public function test_store_destfile_from_string() {
 293          $this->resetAfterTest();
 294  
 295          $sourcefile = $this->create_stored_file();
 296          $conversion = new conversion(0, (object) [
 297              'sourcefileid' => $sourcefile->get_id(),
 298              'targetformat' => 'pdf',
 299          ]);
 300  
 301          $fixture = 'Example content';
 302          $conversion->store_destfile_from_string($fixture);
 303  
 304          $destfile = $conversion->get_destfile();
 305          $this->assertEquals($fixture, $destfile->get_content());
 306      }
 307  
 308      /**
 309       * Ensure that store_destfile_from_string stores the file as expected when
 310       * an existing destfile is found.
 311       */
 312      public function test_store_destfile_from_string_delete_existing() {
 313          $this->resetAfterTest();
 314  
 315          $sourcefile = $this->create_stored_file();
 316          $conversion = new conversion(0, (object) [
 317              'sourcefileid' => $sourcefile->get_id(),
 318              'targetformat' => 'pdf',
 319          ]);
 320  
 321          $record = [
 322              'contextid' => \context_system::instance()->id,
 323              'component' => 'core',
 324              'filearea'  => 'documentconversion',
 325              'itemid'    => 0,
 326              'filepath'  => '/pdf/',
 327          ];
 328          $existingfile = $this->create_stored_file('foo', $sourcefile->get_contenthash(), $record);
 329  
 330          $fixture = 'Example content';
 331          $conversion->store_destfile_from_string($fixture);
 332  
 333          $destfile = $conversion->get_destfile();
 334          $this->assertEquals($fixture, $destfile->get_content());
 335      }
 336  
 337      /**
 338       * Ensure that the get_status functions cast the status to integer correctly.
 339       */
 340      public function test_get_status() {
 341          $conversion = new conversion(0, (object) [
 342              'status' => (string) 1,
 343          ]);
 344  
 345          $this->assertIsInt($conversion->get('status'));
 346      }
 347  
 348      /**
 349       * Ensure that get_converter_instance returns false when no converter is set.
 350       */
 351      public function test_get_converter_instance_none_set() {
 352          $conversion = new conversion(0, (object) []);
 353          $this->assertFalse($conversion->get_converter_instance());
 354      }
 355  
 356      /**
 357       * Ensure that get_converter_instance returns false when no valid converter is set.
 358       */
 359      public function test_get_converter_instance_invalid_set() {
 360          $conversion = new conversion(0, (object) [
 361              'converter' => '\\fileconverter_not_a_valid_converter\\converter',
 362          ]);
 363          $this->assertFalse($conversion->get_converter_instance());
 364      }
 365  
 366      /**
 367       * Ensure that get_converter_instance returns an instance when a valid converter is set.
 368       */
 369      public function test_get_converter_instance_valid_set() {
 370          $conversion = new conversion(0, (object) [
 371              'converter' => \fileconverter_unoconv\converter::class,
 372          ]);
 373          $this->assertInstanceOf(\fileconverter_unoconv\converter::class, $conversion->get_converter_instance());
 374      }
 375  
 376      /**
 377       * Test that all old conversion records are removed periodically.
 378       */
 379      public function test_remove_old_conversion_records_old() {
 380          $this->resetAfterTest();
 381          global $DB;
 382  
 383          $sourcefile = $this->create_stored_file();
 384          $conversion = new conversion(0, (object) [
 385                  'sourcefileid' => $sourcefile->get_id(),
 386                  'targetformat' => 'pdf',
 387              ]);
 388          $conversion->create();
 389          $DB->set_field(conversion::TABLE, 'timemodified', time() - YEARSECS);
 390  
 391          conversion::remove_old_conversion_records();
 392  
 393          $this->assertEquals(0, $DB->count_records(conversion::TABLE));
 394      }
 395  
 396      /**
 397       * Test that all old conversion records are removed periodically.
 398       */
 399      public function test_remove_old_conversion_records_young() {
 400          $this->resetAfterTest();
 401          global $DB;
 402  
 403          $sourcefile = $this->create_stored_file();
 404          $conversion = new conversion(0, (object) [
 405                  'sourcefileid' => $sourcefile->get_id(),
 406                  'targetformat' => 'pdf',
 407              ]);
 408          $conversion->create();
 409          $DB->set_field(conversion::TABLE, 'timemodified', time() - DAYSECS);
 410  
 411          conversion::remove_old_conversion_records();
 412  
 413          $this->assertEquals(1, $DB->count_records(conversion::TABLE));
 414      }
 415  
 416      /**
 417       * Test orphan records are removed.
 418       */
 419      public function test_remove_orphan_records() {
 420          global $DB;
 421          $this->resetAfterTest();
 422  
 423          $sf1 = $this->create_stored_file('1', '1');
 424          $sf2 = $this->create_stored_file('2', '2');
 425          $sf3 = $this->create_stored_file('3', '3');
 426          $c1 = new conversion(0, (object) ['sourcefileid' => $sf1->get_id(), 'targetformat' => 'pdf']);
 427          $c1->create();
 428          $c2 = new conversion(0, (object) ['sourcefileid' => $sf2->get_id(), 'targetformat' => 'pdf']);
 429          $c2->create();
 430          $c3 = new conversion(0, (object) ['sourcefileid' => $sf3->get_id(), 'targetformat' => 'pdf']);
 431          $c3->create();
 432  
 433          $this->assertTrue(conversion::record_exists($c1->get('id')));
 434          $this->assertTrue(conversion::record_exists($c2->get('id')));
 435          $this->assertTrue(conversion::record_exists($c3->get('id')));
 436  
 437          // Nothing should happen here.
 438          conversion::remove_orphan_records();
 439          $this->assertTrue(conversion::record_exists($c1->get('id')));
 440          $this->assertTrue(conversion::record_exists($c2->get('id')));
 441          $this->assertTrue(conversion::record_exists($c3->get('id')));
 442  
 443          // Delete file #2.
 444          $sf2->delete();
 445          conversion::remove_orphan_records();
 446          $this->assertTrue(conversion::record_exists($c1->get('id')));
 447          $this->assertFalse(conversion::record_exists($c2->get('id')));
 448          $this->assertTrue(conversion::record_exists($c3->get('id')));
 449  
 450          // Delete file #1, #3.
 451          $sf1->delete();
 452          $sf3->delete();
 453          conversion::remove_orphan_records();
 454          $this->assertFalse(conversion::record_exists($c1->get('id')));
 455          $this->assertFalse(conversion::record_exists($c2->get('id')));
 456          $this->assertFalse(conversion::record_exists($c3->get('id')));
 457      }
 458  }