Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   1  <?php
   2  // This file is part of Moodle - https://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 assignfeedback_editpdf;
  18  
  19  use mod_assign_test_generator;
  20  use advanced_testcase;
  21  use ReflectionMethod;
  22  
  23  defined('MOODLE_INTERNAL') || die();
  24  
  25  global $CFG;
  26  require_once($CFG->dirroot . '/mod/assign/tests/generator.php');
  27  
  28  /**
  29   * Unit tests for document services.
  30   *
  31   * @package    assignfeedback_editpdf
  32   * @category   test
  33   * @covers     \assignfeedback_editpdf\document_services
  34   * @copyright  2022 Mikhail Golenkov <mikhailgolenkov@catalyst-au.net>
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class document_services_test extends advanced_testcase {
  38      use mod_assign_test_generator;
  39  
  40      /**
  41       * Test that the save file method saves the file.
  42       * @covers ::save_file()
  43       */
  44      public function test_save_file_saves_the_file() {
  45          global $DB;
  46          $this->resetAfterTest();
  47  
  48          $course = $this->getDataGenerator()->create_course();
  49          $assign = $this->create_instance($course);
  50          $user = $this->getDataGenerator()->create_user();
  51          $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
  52  
  53          $method = new ReflectionMethod('\assignfeedback_editpdf\document_services', 'save_file');
  54          $method->setAccessible(true);
  55  
  56          $filearea = document_services::TMP_ROTATED_JPG_FILEAREA;
  57          $content = 'some random content';
  58          $tempfile = make_temp_directory('assignfeedback_editpdf') . DIRECTORY_SEPARATOR . 'mock.file';
  59          file_put_contents($tempfile, $content);
  60  
  61          // Invoke the method and confirm, that the file is saved.
  62          $file1 = $method->invoke(null, $assign, $user->id, 1, $filearea, $tempfile);
  63          $this->assertInstanceOf('stored_file', $file1);
  64          $this->assertEquals(1, $DB->count_records('files', ['id' => $file1->get_id()]));
  65  
  66          // Invoke the method again and confirm, that exising file is returned.
  67          $file2 = $method->invoke(null, $assign, $user->id, 1, $filearea, $tempfile);
  68          $this->assertEquals($file1->get_id(), $file2->get_id());
  69      }
  70  
  71      /**
  72       * Test that save_rotated_image_file() method saves the file.
  73       * @covers ::save_rotated_image_file()
  74       */
  75      public function test_save_rotated_image_file_saves_the_file() {
  76          global $CFG, $DB;
  77          $this->resetAfterTest();
  78  
  79          $course = $this->getDataGenerator()->create_course();
  80          $assign = $this->create_instance($course);
  81          $user = $this->getDataGenerator()->create_user();
  82          $this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
  83  
  84          $method = new ReflectionMethod('\assignfeedback_editpdf\document_services', 'save_rotated_image_file');
  85          $method->setAccessible(true);
  86  
  87          $imagecontent = file_get_contents($CFG->dirroot . '/lib/filestorage/tests/fixtures/testimage.png');
  88          $imageresource = imagecreatefromstring($imagecontent);
  89  
  90          // Invoke the method and confirm, that the file is saved.
  91          $file1 = $method->invoke(null, $assign, $user->id, 1, $imageresource, 'testimage.png');
  92          $this->assertInstanceOf('stored_file', $file1);
  93          $this->assertEquals(1, $DB->count_records('files', ['id' => $file1->get_id()]));
  94  
  95          // Invoke the method again and confirm, that exising file is returned.
  96          $file2 = $method->invoke(null, $assign, $user->id, 1, $imageresource, 'testimage.png');
  97          $this->assertEquals($file1->get_id(), $file2->get_id());
  98      }
  99  
 100      /**
 101       * Test that get_combined_document_for_attempt() method rotates the image only once.
 102       * @covers ::get_combined_document_for_attempt()
 103       */
 104      public function test_get_combined_document_for_attempt_rotates_image() {
 105          global $CFG, $DB;
 106          $this->resetAfterTest();
 107  
 108          $course = $this->getDataGenerator()->create_course();
 109          $assignparams = [
 110              'assignsubmission_file_enabled' => 1,
 111              'assignsubmission_file_maxfiles' => 1,
 112              'assignsubmission_file_maxsizebytes' => 1024 * 1024,
 113          ];
 114          $assign = $this->create_instance($course, $assignparams);
 115          $student = $this->getDataGenerator()->create_user();
 116          $this->getDataGenerator()->enrol_user($student->id, $course->id, 'student');
 117          $this->setUser($student);
 118  
 119          $notices = [];
 120          $submission = $assign->get_user_submission($student->id, true, 1);
 121          $data = (object) ['files_filemanager' => $submission->id];
 122          $assign->save_submission($data, $notices);
 123  
 124          // This image was manually rotated to be upside down. Also, Orientation, ExifImageWidth
 125          // and ExifImageLength EXIF tags were written into its metadata.
 126          // This is needed to make sure that this image will be rotated by stored_file::rotate_image()
 127          // and stored as a new rotated file.
 128          $filename = 'testimage_rotated.jpg';
 129          $filepath = $CFG->dirroot . '/lib/filestorage/tests/fixtures/' . $filename;
 130          $filerecord = [
 131              'contextid' => $assign->get_context()->id,
 132              'component' => 'assignsubmission_file',
 133              'filearea'  => ASSIGNSUBMISSION_FILE_FILEAREA,
 134              'itemid'    => $submission->id,
 135              'filepath'  => '/',
 136              'filename'  => $filename,
 137          ];
 138          $fs = get_file_storage();
 139          $fs->create_file_from_pathname($filerecord, $filepath);
 140  
 141          $params = [
 142              'filearea' => document_services::TMP_ROTATED_JPG_FILEAREA,
 143              'component' => document_services::COMPONENT,
 144              'filename' => $filename,
 145          ];
 146  
 147          // Combine the document and get the rotated file.
 148          document_services::get_combined_document_for_attempt($assign, $student->id, 1);
 149          $records = $DB->get_records('files', $params);
 150          $this->assertCount(1, $records);
 151          $record1 = reset($records);
 152  
 153          // Polling file converters do this twice: one call to start a conversion and another one
 154          // to poll the converted file. So we combine the document again here.
 155          document_services::get_combined_document_for_attempt($assign, $student->id, 1);
 156          $records = $DB->get_records('files', $params);
 157          $this->assertCount(1, $records);
 158          $record2 = reset($records);
 159  
 160          // Confirm, that the second get_combined_document_for_attempt() call doesn't create new
 161          // rotated file and re-uses the one that was created as part of the first
 162          // get_combined_document_for_attempt() call.
 163          $this->assertEquals($record1->id, $record2->id);
 164      }
 165  }