cleanup = []; } protected function tearDown(): void { foreach ($this->cleanup as $file) { if (is_scalar($file) && file_exists($file)) { unlink($file); } } } public function invalidStreams() { return [ 'null' => [null], 'true' => [true], 'false' => [false], 'int' => [1], 'float' => [1.1], 'array' => [['filename']], 'object' => [(object) ['filename']], ]; } /** * @dataProvider invalidStreams */ public function testRaisesExceptionOnInvalidStreamOrFile($streamOrFile): void { $this->expectException(\InvalidArgumentException::class); new UploadedFile($streamOrFile, 0, UPLOAD_ERR_OK); } public function testGetStreamReturnsOriginalStreamObject(): void { $stream = new Stream(fopen('php://temp', 'r')); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); self::assertSame($stream, $upload->getStream()); } public function testGetStreamReturnsWrappedPhpStream(): void { $stream = fopen('php://temp', 'wb+'); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); $uploadStream = $upload->getStream()->detach(); self::assertSame($stream, $uploadStream); } public function testGetStreamReturnsStreamForFile(): void { $this->cleanup[] = $stream = tempnam(sys_get_temp_dir(), 'stream_file'); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); $uploadStream = $upload->getStream(); $r = new ReflectionProperty($uploadStream, 'filename'); $r->setAccessible(true); self::assertSame($stream, $r->getValue($uploadStream)); } public function testSuccessful(): void { $stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!'); $upload = new UploadedFile($stream, $stream->getSize(), UPLOAD_ERR_OK, 'filename.txt', 'text/plain'); self::assertSame($stream->getSize(), $upload->getSize()); self::assertSame('filename.txt', $upload->getClientFilename()); self::assertSame('text/plain', $upload->getClientMediaType()); $this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'successful'); $upload->moveTo($to); self::assertFileExists($to); self::assertSame($stream->__toString(), file_get_contents($to)); } public function invalidMovePaths(): iterable { return [ 'null' => [null], 'true' => [true], 'false' => [false], 'int' => [1], 'float' => [1.1], 'empty' => [''], 'array' => [['filename']], 'object' => [(object) ['filename']], ]; } /** * @dataProvider invalidMovePaths */ public function testMoveRaisesExceptionForInvalidPath($path): void { $stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!'); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('path'); $upload->moveTo($path); } public function testMoveCannotBeCalledMoreThanOnce(): void { $stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!'); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); $this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'diac'); $upload->moveTo($to); self::assertFileExists($to); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('moved'); $upload->moveTo($to); } public function testCannotRetrieveStreamAfterMove(): void { $stream = \GuzzleHttp\Psr7\Utils::streamFor('Foo bar!'); $upload = new UploadedFile($stream, 0, UPLOAD_ERR_OK); $this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'diac'); $upload->moveTo($to); self::assertFileExists($to); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('moved'); $upload->getStream(); } public function nonOkErrorStatus(): iterable { return [ 'UPLOAD_ERR_INI_SIZE' => [UPLOAD_ERR_INI_SIZE], 'UPLOAD_ERR_FORM_SIZE' => [UPLOAD_ERR_FORM_SIZE], 'UPLOAD_ERR_PARTIAL' => [UPLOAD_ERR_PARTIAL], 'UPLOAD_ERR_NO_FILE' => [UPLOAD_ERR_NO_FILE], 'UPLOAD_ERR_NO_TMP_DIR' => [UPLOAD_ERR_NO_TMP_DIR], 'UPLOAD_ERR_CANT_WRITE' => [UPLOAD_ERR_CANT_WRITE], 'UPLOAD_ERR_EXTENSION' => [UPLOAD_ERR_EXTENSION], ]; } /** * @dataProvider nonOkErrorStatus */ public function testConstructorDoesNotRaiseExceptionForInvalidStreamWhenErrorStatusPresent($status): void { $uploadedFile = new UploadedFile('not ok', 0, $status); self::assertSame($status, $uploadedFile->getError()); } /** * @dataProvider nonOkErrorStatus */ public function testMoveToRaisesExceptionWhenErrorStatusPresent($status): void { $uploadedFile = new UploadedFile('not ok', 0, $status); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('upload error'); $uploadedFile->moveTo(__DIR__.'/'.bin2hex(random_bytes(20))); } /** * @dataProvider nonOkErrorStatus */ public function testGetStreamRaisesExceptionWhenErrorStatusPresent($status): void { $uploadedFile = new UploadedFile('not ok', 0, $status); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('upload error'); $uploadedFile->getStream(); } public function testMoveToCreatesStreamIfOnlyAFilenameWasProvided(): void { $this->cleanup[] = $from = tempnam(sys_get_temp_dir(), 'copy_from'); $this->cleanup[] = $to = tempnam(sys_get_temp_dir(), 'copy_to'); copy(__FILE__, $from); $uploadedFile = new UploadedFile($from, 100, UPLOAD_ERR_OK, basename($from), 'text/plain'); $uploadedFile->moveTo($to); self::assertFileEquals(__FILE__, $to); } }