fails( File::default(), 'foo', ['validation.file'], ); $this->passes( File::default(), UploadedFile::fake()->create('foo.bar'), ); $this->passes(File::default(), null); } protected function fails($rule, $values, $messages) { $this->assertValidationRules($rule, $values, false, $messages); } protected function assertValidationRules($rule, $values, $result, $messages) { $values = Arr::wrap($values); foreach ($values as $value) { $v = new Validator( resolve('translator'), ['my_file' => $value], ['my_file' => is_object($rule) ? clone $rule : $rule] ); $this->assertSame($result, $v->passes()); $this->assertSame( $result ? [] : ['my_file' => $messages], $v->messages()->toArray() ); } } protected function passes($rule, $values) { $this->assertValidationRules($rule, $values, true, []); } public function testSingleMimetype() { $this->fails( File::types('text/plain'), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.mimetypes'] ); $this->passes( File::types('image/png'), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testMultipleMimeTypes() { $this->fails( File::types(['text/plain', 'image/jpeg']), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.mimetypes'] ); $this->passes( File::types(['text/plain', 'image/png']), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testSingleMime() { $this->fails( File::types('txt'), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.mimes'] ); $this->passes( File::types('png'), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testMultipleMimes() { $this->fails( File::types(['png', 'jpg', 'jpeg', 'svg']), UploadedFile::fake()->createWithContent('foo.txt', 'Hello World!'), ['validation.mimes'] ); $this->passes( File::types(['png', 'jpg', 'jpeg', 'svg']), [ UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), UploadedFile::fake()->createWithContent('foo.svg', file_get_contents(__DIR__.'/fixtures/image.svg')), ] ); } public function testMixOfMimetypesAndMimes() { $this->fails( File::types(['png', 'image/png']), UploadedFile::fake()->createWithContent('foo.txt', 'Hello World!'), ['validation.mimetypes', 'validation.mimes'] ); $this->passes( File::types(['png', 'image/png']), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testSingleExtension() { $this->fails( File::default()->extensions('png'), UploadedFile::fake()->createWithContent('foo', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.extensions'] ); $this->fails( File::default()->extensions('png'), UploadedFile::fake()->createWithContent('foo.jpg', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.extensions'] ); $this->fails( File::default()->extensions('jpeg'), UploadedFile::fake()->createWithContent('foo.jpg', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.extensions'] ); $this->passes( File::default()->extensions('png'), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testMultipleExtensions() { $this->fails( File::default()->extensions(['png', 'jpeg', 'jpg']), UploadedFile::fake()->createWithContent('foo', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.extensions'] ); $this->fails( File::default()->extensions(['png', 'jpeg']), UploadedFile::fake()->createWithContent('foo.jpg', file_get_contents(__DIR__.'/fixtures/image.png')), ['validation.extensions'] ); $this->passes( File::default()->extensions(['png', 'jpeg', 'jpg']), UploadedFile::fake()->createWithContent('foo.png', file_get_contents(__DIR__.'/fixtures/image.png')), ); } public function testImage() { $this->fails( File::image(), UploadedFile::fake()->createWithContent('foo.txt', 'Hello World!'), ['validation.image'] ); $this->passes( File::image(), UploadedFile::fake()->image('foo.png'), ); } public function testImageFailsOnSvgByDefault() { $maliciousSvgFileWithXSS = UploadedFile::fake()->createWithContent( name: 'foo.svg', content: <<<'XML' XSS Logo XML ); $this->fails( File::image(), $maliciousSvgFileWithXSS, ['validation.image'] ); $this->fails( Rule::imageFile(), $maliciousSvgFileWithXSS, ['validation.image'] ); $this->passes( File::image(allowSvg: true), $maliciousSvgFileWithXSS ); $this->passes( Rule::imageFile(allowSvg: true), $maliciousSvgFileWithXSS ); } public function testSize() { $this->fails( File::default()->size(1024), [ UploadedFile::fake()->create('foo.txt', 1025), UploadedFile::fake()->create('foo.txt', 1023), ], ['validation.size.file'] ); $this->passes( File::default()->size(1024), UploadedFile::fake()->create('foo.txt', 1024), ); } public function testBetween() { $this->fails( File::default()->between(1024, 2048), [ UploadedFile::fake()->create('foo.txt', 1023), UploadedFile::fake()->create('foo.txt', 2049), ], ['validation.between.file'] ); $this->passes( File::default()->between(1024, 2048), [ UploadedFile::fake()->create('foo.txt', 1024), UploadedFile::fake()->create('foo.txt', 2048), UploadedFile::fake()->create('foo.txt', 1025), UploadedFile::fake()->create('foo.txt', 2047), ] ); } public function testMin() { $this->fails( File::default()->min(1024), UploadedFile::fake()->create('foo.txt', 1023), ['validation.min.file'] ); $this->passes( File::default()->min(1024), [ UploadedFile::fake()->create('foo.txt', 1024), UploadedFile::fake()->create('foo.txt', 1025), UploadedFile::fake()->create('foo.txt', 2048), ] ); } public function testMinWithHumanReadableSize() { $this->fails( File::default()->min('1024kb'), UploadedFile::fake()->create('foo.txt', 1023), ['validation.min.file'] ); $this->passes( File::default()->min('1024kb'), [ UploadedFile::fake()->create('foo.txt', 1024), UploadedFile::fake()->create('foo.txt', 1025), UploadedFile::fake()->create('foo.txt', 2048), ] ); } public function testMax() { $this->fails( File::default()->max(1024), UploadedFile::fake()->create('foo.txt', 1025), ['validation.max.file'] ); $this->passes( File::default()->max(1024), [ UploadedFile::fake()->create('foo.txt', 1024), UploadedFile::fake()->create('foo.txt', 1023), UploadedFile::fake()->create('foo.txt', 512), ] ); } public function testMaxWithHumanReadableSize() { $this->fails( File::default()->max('1024kb'), UploadedFile::fake()->create('foo.txt', 1025), ['validation.max.file'] ); $this->passes( File::default()->max('1024kb'), [ UploadedFile::fake()->create('foo.txt', 1024), UploadedFile::fake()->create('foo.txt', 1023), UploadedFile::fake()->create('foo.txt', 512), ] ); } public function testMaxWithHumanReadableSizeAndMultipleValue() { $this->fails( File::default()->max('1mb'), UploadedFile::fake()->create('foo.txt', 1025), ['validation.max.file'] ); $this->passes( File::default()->max('1mb'), [ UploadedFile::fake()->create('foo.txt', 1000), UploadedFile::fake()->create('foo.txt', 999), UploadedFile::fake()->create('foo.txt', 512), ] ); } public function testEncoding() { // ASCII file containing UTF-8. $this->fails( File::default()->encoding('ascii'), UploadedFile::fake()->createWithContent('foo.txt', '✌️'), ['validation.encoding'], ); // UTF-8 file containing invalid UTF-8 byte sequence. $this->fails( File::default()->encoding('utf-8'), UploadedFile::fake()->createWithContent('foo.txt', "\xf0\x28\x8c\x28"), ['validation.encoding'], ); $this->passes( File::default()->encoding('utf-8'), UploadedFile::fake()->createWithContent('foo.txt', '✌️'), ); $this->passes( File::default()->encoding('utf-8'), [ UploadedFile::fake()->createWithContent('foo-1.txt', '✌️'), UploadedFile::fake()->createWithContent('foo-2.txt', '👍'), ] ); } public function testEncodingWithInvalidParameter() { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Validation rule encoding parameter [FOOBAR] is not a valid encoding.'); // Invalid encoding. $this->fails( File::default()->encoding('FOOBAR'), UploadedFile::fake()->createWithContent('foo.txt', ''), ['validation.encoding'], ); } public function testMacro() { File::macro('toDocument', function () { return static::default()->rules('mimes:txt,csv'); }); $this->fails( File::toDocument(), UploadedFile::fake()->create('foo.png'), ['validation.mimes'] ); $this->passes( File::toDocument(), [ UploadedFile::fake()->create('foo.txt'), UploadedFile::fake()->create('foo.csv'), ] ); } public function testItUsesTheCorrectValidationMessageForFile(): void { file_put_contents($path = __DIR__.'/test.json', 'this-is-a-test'); $file = new \Illuminate\Http\File($path); $this->fails( ['max:0'], $file, ['validation.max.file'] ); unlink($path); } public function testItCanSetDefaultUsing() { $this->assertInstanceOf(File::class, File::default()); File::defaults(function () { return File::types('txt')->max(12 * 1024); }); $this->fails( File::default(), UploadedFile::fake()->create('foo.png', 13 * 1024), [ 'validation.mimes', 'validation.max.file', ] ); File::defaults(File::image()->between(1024, 2048)); $this->passes( File::default(), UploadedFile::fake()->create('foo.png', 1.5 * 1024), ); } public function testFileSizeConversionWithDifferentUnits() { $this->passes( File::image()->size('5MB'), UploadedFile::fake()->create('foo.png', 5000) ); $this->passes( File::image()->size(' 2gb '), UploadedFile::fake()->create('foo.png', 2 * 1000000) ); $this->passes( File::image()->size('1Tb'), UploadedFile::fake()->create('foo.png', 1000000000) ); $this->expectException(\InvalidArgumentException::class); File::image()->size('10xyz'); } protected function setUp(): void { $container = Container::getInstance(); $container->bind('translator', function () { return new Translator( new ArrayLoader, 'en' ); }); Facade::setFacadeApplication($container); (new ValidationServiceProvider($container))->register(); } protected function tearDown(): void { Container::setInstance(null); Facade::clearResolvedInstances(); Facade::setFacadeApplication(null); parent::tearDown(); } }