Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

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