PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTest.php

https://github.com/jahama/symfony
PHP | 394 lines | 294 code | 69 blank | 31 comment | 3 complexity | 2b4d19b5e2acc6774603ed4eefd35af2 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Validator\Tests\Constraints;
  11. use Symfony\Component\HttpFoundation\File\UploadedFile;
  12. use Symfony\Component\Validator\Constraints\File;
  13. use Symfony\Component\Validator\Constraints\FileValidator;
  14. abstract class FileValidatorTest extends \PHPUnit_Framework_TestCase
  15. {
  16. protected $context;
  17. protected $validator;
  18. protected $path;
  19. protected $file;
  20. protected function setUp()
  21. {
  22. $this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false);
  23. $this->validator = new FileValidator();
  24. $this->validator->initialize($this->context);
  25. $this->path = sys_get_temp_dir().DIRECTORY_SEPARATOR.'FileValidatorTest';
  26. $this->file = fopen($this->path, 'w');
  27. fwrite($this->file, ' ', 1);
  28. }
  29. protected function tearDown()
  30. {
  31. if (is_resource($this->file)) {
  32. fclose($this->file);
  33. }
  34. if (file_exists($this->path)) {
  35. unlink($this->path);
  36. }
  37. $this->context = null;
  38. $this->validator = null;
  39. $this->path = null;
  40. $this->file = null;
  41. }
  42. public function testNullIsValid()
  43. {
  44. $this->context->expects($this->never())
  45. ->method('addViolation');
  46. $this->validator->validate(null, new File());
  47. }
  48. public function testEmptyStringIsValid()
  49. {
  50. $this->context->expects($this->never())
  51. ->method('addViolation');
  52. $this->validator->validate('', new File());
  53. }
  54. /**
  55. * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException
  56. */
  57. public function testExpectsStringCompatibleTypeOrFile()
  58. {
  59. $this->validator->validate(new \stdClass(), new File());
  60. }
  61. public function testValidFile()
  62. {
  63. $this->context->expects($this->never())
  64. ->method('addViolation');
  65. $this->validator->validate($this->path, new File());
  66. }
  67. public function testValidUploadedfile()
  68. {
  69. $this->context->expects($this->never())
  70. ->method('addViolation');
  71. $file = new UploadedFile($this->path, 'originalName', null, null, null, true);
  72. $this->validator->validate($file, new File());
  73. }
  74. public function provideMaxSizeExceededTests()
  75. {
  76. return array(
  77. array(11, 10, '11', '10', 'bytes'),
  78. array(ceil(1.005*1000), ceil(1.005*1000) - 1, '1005', '1004', 'bytes'),
  79. array(ceil(1.005*1000*1000), ceil(1.005*1000*1000) - 1, '1005000', '1004999', 'bytes'),
  80. // round(size) == 1.01kB, limit == 1kB
  81. array(ceil(1.005*1000), 1000, '1.01', '1', 'kB'),
  82. array(ceil(1.005*1000), '1k', '1.01', '1', 'kB'),
  83. // round(size) == 1kB, limit == 1kB -> use bytes
  84. array(ceil(1.004*1000), 1000, '1004', '1000', 'bytes'),
  85. array(ceil(1.004*1000), '1k', '1004', '1000', 'bytes'),
  86. array(1000 + 1, 1000, '1001', '1000', 'bytes'),
  87. array(1000 + 1, '1k', '1001', '1000', 'bytes'),
  88. // round(size) == 1.01MB, limit == 1MB
  89. array(ceil(1.005*1000*1000), 1000*1000, '1.01', '1', 'MB'),
  90. array(ceil(1.005*1000*1000), '1000k', '1.01', '1', 'MB'),
  91. array(ceil(1.005*1000*1000), '1M', '1.01', '1', 'MB'),
  92. // round(size) == 1MB, limit == 1MB -> use kB
  93. array(ceil(1.004*1000*1000), 1000*1000, '1004', '1000', 'kB'),
  94. array(ceil(1.004*1000*1000), '1000k', '1004', '1000', 'kB'),
  95. array(ceil(1.004*1000*1000), '1M', '1004', '1000', 'kB'),
  96. array(1000*1000 + 1, 1000*1000, '1000001', '1000000', 'bytes'),
  97. array(1000*1000 + 1, '1000k', '1000001', '1000000', 'bytes'),
  98. array(1000*1000 + 1, '1M', '1000001', '1000000', 'bytes'),
  99. );
  100. }
  101. /**
  102. * @dataProvider provideMaxSizeExceededTests
  103. */
  104. public function testMaxSizeExceeded($bytesWritten, $limit, $sizeAsString, $limitAsString, $suffix)
  105. {
  106. fseek($this->file, $bytesWritten-1, SEEK_SET);
  107. fwrite($this->file, '0');
  108. fclose($this->file);
  109. $constraint = new File(array(
  110. 'maxSize' => $limit,
  111. 'maxSizeMessage' => 'myMessage',
  112. ));
  113. $this->context->expects($this->once())
  114. ->method('addViolation')
  115. ->with('myMessage', array(
  116. '{{ limit }}' => $limitAsString,
  117. '{{ size }}' => $sizeAsString,
  118. '{{ suffix }}' => $suffix,
  119. '{{ file }}' => $this->path,
  120. ));
  121. $this->validator->validate($this->getFile($this->path), $constraint);
  122. }
  123. public function provideMaxSizeNotExceededTests()
  124. {
  125. return array(
  126. array(10, 10),
  127. array(9, 10),
  128. array(1000, '1k'),
  129. array(1000 - 1, '1k'),
  130. array(1000*1000, '1M'),
  131. array(1000*1000 - 1, '1M'),
  132. );
  133. }
  134. /**
  135. * @dataProvider provideMaxSizeNotExceededTests
  136. */
  137. public function testMaxSizeNotExceeded($bytesWritten, $limit)
  138. {
  139. fseek($this->file, $bytesWritten-1, SEEK_SET);
  140. fwrite($this->file, '0');
  141. fclose($this->file);
  142. $constraint = new File(array(
  143. 'maxSize' => $limit,
  144. 'maxSizeMessage' => 'myMessage',
  145. ));
  146. $this->context->expects($this->never())
  147. ->method('addViolation');
  148. $this->validator->validate($this->getFile($this->path), $constraint);
  149. }
  150. /**
  151. * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
  152. */
  153. public function testInvalidMaxSize()
  154. {
  155. $constraint = new File(array(
  156. 'maxSize' => '1abc',
  157. ));
  158. $this->validator->validate($this->path, $constraint);
  159. }
  160. public function testValidMimeType()
  161. {
  162. $file = $this
  163. ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
  164. ->disableOriginalConstructor()
  165. ->getMock()
  166. ;
  167. $file
  168. ->expects($this->once())
  169. ->method('getPathname')
  170. ->will($this->returnValue($this->path))
  171. ;
  172. $file
  173. ->expects($this->once())
  174. ->method('getMimeType')
  175. ->will($this->returnValue('image/jpg'))
  176. ;
  177. $this->context->expects($this->never())
  178. ->method('addViolation');
  179. $constraint = new File(array(
  180. 'mimeTypes' => array('image/png', 'image/jpg'),
  181. ));
  182. $this->validator->validate($file, $constraint);
  183. }
  184. public function testValidWildcardMimeType()
  185. {
  186. $file = $this
  187. ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
  188. ->disableOriginalConstructor()
  189. ->getMock()
  190. ;
  191. $file
  192. ->expects($this->once())
  193. ->method('getPathname')
  194. ->will($this->returnValue($this->path))
  195. ;
  196. $file
  197. ->expects($this->once())
  198. ->method('getMimeType')
  199. ->will($this->returnValue('image/jpg'))
  200. ;
  201. $this->context->expects($this->never())
  202. ->method('addViolation');
  203. $constraint = new File(array(
  204. 'mimeTypes' => array('image/*'),
  205. ));
  206. $this->validator->validate($file, $constraint);
  207. }
  208. public function testInvalidMimeType()
  209. {
  210. $file = $this
  211. ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
  212. ->disableOriginalConstructor()
  213. ->getMock()
  214. ;
  215. $file
  216. ->expects($this->once())
  217. ->method('getPathname')
  218. ->will($this->returnValue($this->path))
  219. ;
  220. $file
  221. ->expects($this->once())
  222. ->method('getMimeType')
  223. ->will($this->returnValue('application/pdf'))
  224. ;
  225. $constraint = new File(array(
  226. 'mimeTypes' => array('image/png', 'image/jpg'),
  227. 'mimeTypesMessage' => 'myMessage',
  228. ));
  229. $this->context->expects($this->once())
  230. ->method('addViolation')
  231. ->with('myMessage', array(
  232. '{{ type }}' => '"application/pdf"',
  233. '{{ types }}' => '"image/png", "image/jpg"',
  234. '{{ file }}' => $this->path,
  235. ));
  236. $this->validator->validate($file, $constraint);
  237. }
  238. public function testInvalidWildcardMimeType()
  239. {
  240. $file = $this
  241. ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
  242. ->disableOriginalConstructor()
  243. ->getMock()
  244. ;
  245. $file
  246. ->expects($this->once())
  247. ->method('getPathname')
  248. ->will($this->returnValue($this->path))
  249. ;
  250. $file
  251. ->expects($this->once())
  252. ->method('getMimeType')
  253. ->will($this->returnValue('application/pdf'))
  254. ;
  255. $constraint = new File(array(
  256. 'mimeTypes' => array('image/*', 'image/jpg'),
  257. 'mimeTypesMessage' => 'myMessage',
  258. ));
  259. $this->context->expects($this->once())
  260. ->method('addViolation')
  261. ->with('myMessage', array(
  262. '{{ type }}' => '"application/pdf"',
  263. '{{ types }}' => '"image/*", "image/jpg"',
  264. '{{ file }}' => $this->path,
  265. ));
  266. $this->validator->validate($file, $constraint);
  267. }
  268. public function testDisallowEmpty()
  269. {
  270. ftruncate($this->file, 0);
  271. $constraint = new File(array(
  272. 'disallowEmptyMessage' => 'myMessage',
  273. ));
  274. $this->context->expects($this->once())
  275. ->method('addViolation')
  276. ->with('myMessage');
  277. $this->validator->validate($this->getFile($this->path), $constraint);
  278. }
  279. /**
  280. * @dataProvider uploadedFileErrorProvider
  281. */
  282. public function testUploadedFileError($error, $message, array $params = array(), $maxSize = null)
  283. {
  284. $file = new UploadedFile('/path/to/file', 'originalName', 'mime', 0, $error);
  285. $constraint = new File(array(
  286. $message => 'myMessage',
  287. 'maxSize' => $maxSize
  288. ));
  289. $this->context->expects($this->once())
  290. ->method('addViolation')
  291. ->with('myMessage', $params);
  292. $this->validator->validate($file, $constraint);
  293. }
  294. public function uploadedFileErrorProvider()
  295. {
  296. $tests = array(
  297. array(UPLOAD_ERR_FORM_SIZE, 'uploadFormSizeErrorMessage'),
  298. array(UPLOAD_ERR_PARTIAL, 'uploadPartialErrorMessage'),
  299. array(UPLOAD_ERR_NO_FILE, 'uploadNoFileErrorMessage'),
  300. array(UPLOAD_ERR_NO_TMP_DIR, 'uploadNoTmpDirErrorMessage'),
  301. array(UPLOAD_ERR_CANT_WRITE, 'uploadCantWriteErrorMessage'),
  302. array(UPLOAD_ERR_EXTENSION, 'uploadExtensionErrorMessage'),
  303. );
  304. if (class_exists('Symfony\Component\HttpFoundation\File\UploadedFile')) {
  305. // when no maxSize is specified on constraint, it should use the ini value
  306. $tests[] = array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', array(
  307. '{{ limit }}' => UploadedFile::getMaxFilesize(),
  308. '{{ suffix }}' => 'bytes',
  309. ));
  310. // it should use the smaller limitation (maxSize option in this case)
  311. $tests[] = array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', array(
  312. '{{ limit }}' => 1,
  313. '{{ suffix }}' => 'bytes',
  314. ), '1');
  315. // it correctly parses the maxSize option and not only uses simple string comparison
  316. // 1000M should be bigger than the ini value
  317. $tests[] = array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', array(
  318. '{{ limit }}' => UploadedFile::getMaxFilesize(),
  319. '{{ suffix }}' => 'bytes',
  320. ), '1000M');
  321. }
  322. return $tests;
  323. }
  324. abstract protected function getFile($filename);
  325. }