1<?php
2
3namespace Drupal\Tests\file\Kernel;
4
5use Drupal\file\Entity\File;
6
7/**
8 * Tests the functions used to validate uploaded files.
9 *
10 * @group file
11 */
12class ValidatorTest extends FileManagedUnitTestBase {
13
14  /**
15   * An image file.
16   *
17   * @var \Drupal\file\FileInterface
18   */
19  protected $image;
20
21  /**
22   * A file which is not an image.
23   *
24   * @var \Drupal\file\Entity\File
25   */
26  protected $nonImage;
27
28  protected function setUp() {
29    parent::setUp();
30
31    $this->image = File::create();
32    $this->image->setFileUri('core/misc/druplicon.png');
33    /** @var \Drupal\Core\File\FileSystemInterface $file_system */
34    $file_system = \Drupal::service('file_system');
35    $this->image->setFilename($file_system->basename($this->image->getFileUri()));
36
37    $this->nonImage = File::create();
38    $this->nonImage->setFileUri('core/assets/vendor/jquery/jquery.min.js');
39    $this->nonImage->setFilename($file_system->basename($this->nonImage->getFileUri()));
40  }
41
42  /**
43   * Test the file_validate_extensions() function.
44   */
45  public function testFileValidateExtensions() {
46    $file = File::create(['filename' => 'asdf.txt']);
47    $errors = file_validate_extensions($file, 'asdf txt pork');
48    $this->assertCount(0, $errors, 'Valid extension accepted.');
49
50    $file->setFilename('asdf.txt');
51    $errors = file_validate_extensions($file, 'exe png');
52    $this->assertCount(1, $errors, 'Invalid extension blocked.');
53  }
54
55  /**
56   * This ensures a specific file is actually an image.
57   */
58  public function testFileValidateIsImage() {
59    $this->assertFileExists($this->image->getFileUri());
60    $errors = file_validate_is_image($this->image);
61    $this->assertCount(0, $errors, 'No error reported for our image file.');
62
63    $this->assertFileExists($this->nonImage->getFileUri());
64    $errors = file_validate_is_image($this->nonImage);
65    $this->assertCount(1, $errors, 'An error reported for our non-image file.');
66  }
67
68  /**
69   * This ensures the resolution of a specific file is within bounds.
70   *
71   * The image will be resized if it's too large.
72   */
73  public function testFileValidateImageResolution() {
74    // Non-images.
75    $errors = file_validate_image_resolution($this->nonImage);
76    $this->assertCount(0, $errors, 'Should not get any errors for a non-image file.');
77    $errors = file_validate_image_resolution($this->nonImage, '50x50', '100x100');
78    $this->assertCount(0, $errors, 'Do not check the resolution on non files.');
79
80    // Minimum size.
81    $errors = file_validate_image_resolution($this->image);
82    $this->assertCount(0, $errors, 'No errors for an image when there is no minimum or maximum resolution.');
83    $errors = file_validate_image_resolution($this->image, 0, '200x1');
84    $this->assertCount(1, $errors, 'Got an error for an image that was not wide enough.');
85    $errors = file_validate_image_resolution($this->image, 0, '1x200');
86    $this->assertCount(1, $errors, 'Got an error for an image that was not tall enough.');
87    $errors = file_validate_image_resolution($this->image, 0, '200x200');
88    $this->assertCount(1, $errors, 'Small images report an error.');
89
90    // Maximum size.
91    if ($this->container->get('image.factory')->getToolkitId()) {
92      // Copy the image so that the original doesn't get resized.
93      copy('core/misc/druplicon.png', 'temporary://druplicon.png');
94      $this->image->setFileUri('temporary://druplicon.png');
95
96      $errors = file_validate_image_resolution($this->image, '10x5');
97      $this->assertCount(0, $errors, 'No errors should be reported when an oversized image can be scaled down.');
98
99      $image = $this->container->get('image.factory')->get($this->image->getFileUri());
100      $this->assertTrue($image->getWidth() <= 10, 'Image scaled to correct width.', 'File');
101      $this->assertTrue($image->getHeight() <= 5, 'Image scaled to correct height.', 'File');
102
103      // Once again, now with negative width and height to force an error.
104      copy('core/misc/druplicon.png', 'temporary://druplicon.png');
105      $this->image->setFileUri('temporary://druplicon.png');
106      $errors = file_validate_image_resolution($this->image, '-10x-5');
107      $this->assertCount(1, $errors, 'An error reported for an oversized image that can not be scaled down.');
108
109      \Drupal::service('file_system')->unlink('temporary://druplicon.png');
110    }
111    else {
112      // TODO: should check that the error is returned if no toolkit is available.
113      $errors = file_validate_image_resolution($this->image, '5x10');
114      $this->assertCount(1, $errors, 'Oversize images that cannot be scaled get an error.');
115    }
116  }
117
118  /**
119   * This will ensure the filename length is valid.
120   */
121  public function testFileValidateNameLength() {
122    // Create a new file entity.
123    $file = File::create();
124
125    // Add a filename with an allowed length and test it.
126    $file->setFilename(str_repeat('x', 240));
127    $this->assertEqual(strlen($file->getFilename()), 240);
128    $errors = file_validate_name_length($file);
129    $this->assertCount(0, $errors, 'No errors reported for 240 length filename.');
130
131    // Add a filename with a length too long and test it.
132    $file->setFilename(str_repeat('x', 241));
133    $errors = file_validate_name_length($file);
134    $this->assertCount(1, $errors, 'An error reported for 241 length filename.');
135
136    // Add a filename with an empty string and test it.
137    $file->setFilename('');
138    $errors = file_validate_name_length($file);
139    $this->assertCount(1, $errors, 'An error reported for 0 length filename.');
140  }
141
142  /**
143   * Test file_validate_size().
144   */
145  public function testFileValidateSize() {
146    // Create a file with a size of 1000 bytes, and quotas of only 1 byte.
147    $file = File::create(['filesize' => 1000]);
148    $errors = file_validate_size($file, 0, 0);
149    $this->assertCount(0, $errors, 'No limits means no errors.');
150    $errors = file_validate_size($file, 1, 0);
151    $this->assertCount(1, $errors, 'Error for the file being over the limit.');
152    $errors = file_validate_size($file, 0, 1);
153    $this->assertCount(1, $errors, 'Error for the user being over their limit.');
154    $errors = file_validate_size($file, 1, 1);
155    $this->assertCount(2, $errors, 'Errors for both the file and their limit.');
156  }
157
158}
159