diff --git a/tests/ApiTest.php b/tests/ApiTest.php index 4e4e1f7..7caaefa 100644 --- a/tests/ApiTest.php +++ b/tests/ApiTest.php @@ -2051,4 +2051,82 @@ final class ApiTest extends TestCase unlink($filePath); } } + + #[Test] + public function uploadFileUsesMultipartForSmallFiles(): void + { + $uploadUrl = 'https://upload.server/path'; + $fileName = 'small.txt'; + $fileContents = 'content'; + $fileHandle = fopen('php://memory', 'w+'); + fwrite($fileHandle, $fileContents); + rewind($fileHandle); + + $smallFileSize = strlen($fileContents); + $expectedResponse = 'multipart-response'; + + $fstatMock = $this->getFunctionMock('BushlanovDev\MaxMessengerBot', 'fstat'); + $fstatMock->expects($this->once())->with($fileHandle)->willReturn(['size' => $smallFileSize]); + + $this->clientMock + ->expects($this->once()) + ->method('multipartUpload') + ->with($uploadUrl, $fileHandle, $fileName) + ->willReturn($expectedResponse); + + $this->clientMock + ->expects($this->never()) + ->method('resumableUpload'); + + $result = $this->api->uploadFile($uploadUrl, $fileHandle, $fileName); + + $this->assertSame($expectedResponse, $result); + fclose($fileHandle); + } + + #[Test] + public function uploadFileUsesResumableForLargeFiles(): void + { + $uploadUrl = 'https://upload.server/path'; + $fileName = 'large.zip'; + $fileHandle = fopen('php://memory', 'w+'); + + rewind($fileHandle); + + $largeFileSize = 10 * 1024 * 1024; + $expectedResponse = 'resumable-response'; + + $fstatMock = $this->getFunctionMock('BushlanovDev\MaxMessengerBot', 'fstat'); + $fstatMock->expects($this->once())->with($fileHandle)->willReturn(['size' => $largeFileSize]); + + $this->clientMock + ->expects($this->once()) + ->method('resumableUpload') + ->with($uploadUrl, $fileHandle, $fileName, $largeFileSize) + ->willReturn($expectedResponse); + + $this->clientMock + ->expects($this->never()) + ->method('multipartUpload'); + + $result = $this->api->uploadFile($uploadUrl, $fileHandle, $fileName); + + $this->assertSame($expectedResponse, $result); + fclose($fileHandle); + } + + #[Test] + public function uploadFileThrowsExceptionWhenFstatFails(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('File handle is not a valid resource.'); + + $fileHandle = fopen('php://memory', 'r'); + + $fstatMock = $this->getFunctionMock('BushlanovDev\MaxMessengerBot', 'fstat'); + $fstatMock->expects($this->once())->with($fileHandle)->willReturn(false); + + $this->api->uploadFile('http://a.b', $fileHandle, 'file.txt'); + fclose($fileHandle); + } } diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 4c2156f..00b901d 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -332,7 +332,7 @@ final class ClientTest extends TestCase $this->requestFactoryMock->method('createRequest')->willReturn($this->requestMock); $this->requestMock->method('withHeader')->willReturn($this->requestMock); $this->requestMock->method('withBody')->willReturn($this->requestMock); - $this->httpClientMock->method('sendRequest')->willReturn($this->responseMock); +// $this->httpClientMock->method('sendRequest')->willReturn($this->responseMock); $this->responseMock->method('getStatusCode')->willReturn(200); $this->streamMock->method('__toString')->willReturn(json_encode($responsePayload)); @@ -409,4 +409,46 @@ final class ClientTest extends TestCase $result = $this->client->multipartUpload($uploadUrl, $fileContents, $fileName); $this->assertSame($rawResponse, $result); } + + #[Test] + public function resumableUploadThrowsExceptionForInvalidResource(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('fileResource must be a valid stream resource.'); + + $this->client->resumableUpload('http://a.b', 'not-a-resource', 'file.txt', 100); + } + + #[Test] + public function resumableUploadThrowsExceptionForZeroFileSize(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('File size must be greater than 0.'); + + $fileResource = fopen('php://memory', 'r'); + $this->client->resumableUpload('http://a.b', $fileResource, 'file.txt', 0); + fclose($fileResource); + } + + #[Test] + public function resumableUploadThrowsNetworkExceptionOnChunkUploadFailure(): void + { + $this->expectException(NetworkException::class); + + $fileResource = fopen('php://memory', 'w+'); + fwrite($fileResource, 'some data'); + rewind($fileResource); + + $this->requestFactoryMock->method('createRequest')->willReturn($this->requestMock); + $this->requestMock->method('withBody')->willReturnSelf(); + $this->requestMock->method('withHeader')->willReturnSelf(); + + $psrException = new class extends \Exception implements ClientExceptionInterface {}; + $this->httpClientMock + ->method('sendRequest') + ->willThrowException($psrException); + + $this->client->resumableUpload('http://a.b', $fileResource, 'file.txt', 9); + fclose($fileResource); + } }