diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a4b27de..63c8b90 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,14 +1,17 @@ name: Tests -on: [push, pull_request] +on: + - push + - pull_request jobs: test: runs-on: ubuntu-latest + strategy: fail-fast: true matrix: - php: [8.2, 8.1] + php: ['8.3', '8.4', '8.5'] stability: [lowest, highest] name: PHP ${{ matrix.php }} - ${{ matrix.stability }} deps diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index f0a412b..d8b2906 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -1,16 +1,18 @@ name: Static Analysis -on: [push, pull_request] +on: + - push + - pull_request jobs: phpstan: name: PHPStan (PHP ${{ matrix.php-version }}) + runs-on: ubuntu-latest strategy: matrix: - php-version: - - '8.2' + php-version: ['8.3', '8.4', '8.5'] steps: - name: Checkout code @@ -27,4 +29,4 @@ jobs: uses: ramsey/composer-install@v3 - name: Run PHPStan - run: 'vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr' + run: vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr diff --git a/composer.json b/composer.json index 750046c..a167888 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ }, "require-dev": { "laravel/pint": "^1.10.1", - "pestphp/pest": "^2.6.3", + "pestphp/pest": "^4.0", "phpstan/phpstan": "^1.10.16" }, "autoload": { diff --git a/phpstan.neon b/phpstan.neon index 2b2eb66..7d875a6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,10 +1,4 @@ parameters: paths: - src - - tests level: 6 - ignoreErrors: - - - message: "#^Call to protected method createConfiguredMock\\(\\) of class PHPUnit\\\\Framework\\\\TestCase\\.$#" - count: 6 - path: tests/ClientTest.php diff --git a/phpunit.xml b/phpunit.xml index 99b05cf..77e94b6 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,32 +1,16 @@ - - - - - - - - tests - - - - src/ diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 9d5638e..165e4aa 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -141,8 +141,7 @@ }); it('can download a file', function () { - $expectedResponse = $this->getMockBuilder(StreamInterface::class) - ->getMock(); + $expectedResponse = $this->createMock(StreamInterface::class); $expectedResponse->expects($this->once()) ->method('isReadable') ->willReturn(true); @@ -165,8 +164,7 @@ }); it('can download a folder as zip', function () { - $expectedResponse = $this->getMockBuilder(StreamInterface::class) - ->getMock(); + $expectedResponse = $this->createMock(StreamInterface::class); $expectedResponse->expects($this->once()) ->method('isReadable') ->willReturn(true); @@ -231,8 +229,7 @@ }); it('can get a thumbnail', function () { - $expectedResponse = $this->getMockBuilder(StreamInterface::class) - ->getMock(); + $expectedResponse = $this->createMock(StreamInterface::class); $mockGuzzle = $this->mockGuzzleRequest( $expectedResponse, @@ -404,38 +401,6 @@ ->and($uploadSessionCursor->offset)->toBe(32); }); -it('can upload a file string chunked', function () { - $content = 'chunk0chunk1chunk2rest'; - $mockClient = $this->mockChunkedUploadClient($content, 6); - - expect($mockClient->uploadChunked('Homework/math/answers.txt', $content, 'add', 6)) - ->toBe(['name' => 'answers.txt']); -})->skip('Must fix method "mockChunkedUploadClient".'); - -it('can upload a file resource chunked', function () { - $content = 'chunk0chunk1chunk2rest'; - $resource = fopen('php://memory', 'r+'); - fwrite($resource, $content); - rewind($resource); - - $mockClient = $this->mockChunkedUploadClient($content, 6); - - expect($mockClient->uploadChunked('Homework/math/answers.txt', $resource, 'add', 6)) - ->toBe(['name' => 'answers.txt']); -})->skip('Must fix method "mockChunkedUploadClient".'); - -it('can upload a tiny file chunked', function () { - $content = 'smallerThenChunkSize'; - $resource = fopen('php://memory', 'r+'); - fwrite($resource, $content); - rewind($resource); - - $mockClient = $this->mockChunkedUploadClient($content, 21); - - expect($mockClient->uploadChunked('Homework/math/answers.txt', $resource, 'add', 21)) - ->toBe(['name' => 'answers.txt']); -})->skip('Must fix method "mockChunkedUploadClient".'); - it('can finish an upload session', function () { $mockGuzzle = $this->mockGuzzleRequest( json_encode([ @@ -531,15 +496,13 @@ }); test('content endpoint request can throw exception', function () { - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->once()) ->method('request') ->willThrowException(new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), - $this->getMockBuilder(ResponseInterface::class)->getMock(), + $this->createMock(RequestInterface::class), + $this->createMock(ResponseInterface::class), )); $client = new Client('test_token', $mockGuzzle); @@ -552,16 +515,14 @@ 'getToken' => 'test_token', ]); - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->exactly(2)) ->method('request') ->willThrowException($e = new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), - $this->getMockBuilder(ResponseInterface::class)->getMock(), + $this->createMock(RequestInterface::class), + $this->createMock(ResponseInterface::class), )); $tokenProvider->expects($this->once()) @@ -575,21 +536,17 @@ })->throws(ClientException::class); test('rpc endpoint request can throw exception with 400 status code', function () { - $mockResponse = $this->getMockBuilder(ResponseInterface::class) - ->getMock(); - $mockResponse->expects($this->any()) - ->method('getStatusCode') - ->willReturn(400); + $mockResponse = $this->createConfiguredMock(ResponseInterface::class, [ + 'getStatusCode' => 400, + ]); - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->once()) ->method('request') ->willThrowException(new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), + $this->createMock(RequestInterface::class), $mockResponse, )); @@ -606,24 +563,18 @@ 'error_summary' => 'Human readable error code', ]; - $mockResponse = $this->getMockBuilder(ResponseInterface::class) - ->getMock(); - $mockResponse->expects($this->any()) - ->method('getStatusCode') - ->willReturn(409); - $mockResponse->expects($this->any()) - ->method('getBody') - ->willReturn($this->createStreamFromString(json_encode($body))); + $mockResponse = $this->createConfiguredMock(ResponseInterface::class, [ + 'getStatusCode' => 409, + 'getBody' => $this->createStreamFromString(json_encode($body)), + ]); - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->once()) ->method('request') ->willThrowException(new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), + $this->createMock(RequestInterface::class), $mockResponse, )); @@ -649,15 +600,13 @@ 'getBody' => $this->createStreamFromString(json_encode($body)), ]); - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->exactly(2)) ->method('request') ->willThrowException($e = new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), + $this->createMock(RequestInterface::class), $mockResponse, )); @@ -697,22 +646,25 @@ 'getBody' => $this->createStreamFromString(json_encode($successBody)), ]); - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $e = new ClientException( 'there was an error', - $this->getMockBuilder(RequestInterface::class)->getMock(), + $this->createMock(RequestInterface::class), $errorResponse, ); + $callCount = 0; $mockGuzzle->expects($this->exactly(2)) ->method('request') - ->willReturnOnConsecutiveCalls( - $this->throwException($e), - $successResponse, - ); + ->willReturnCallback(function () use (&$callCount, $e, $successResponse) { + $callCount++; + if ($callCount === 1) { + throw $e; + } + + return $successResponse; + }); $tokenProvider->expects($this->once()) ->method('refresh') diff --git a/tests/TestCase.php b/tests/TestCase.php index db00af6..f2c1c70 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,7 +9,6 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; use Spatie\Dropbox\Client; -use Spatie\Dropbox\UploadSessionCursor; abstract class TestCase extends BaseTestCase { @@ -18,8 +17,7 @@ abstract class TestCase extends BaseTestCase */ public function mockGuzzleRequest(string|StreamInterface|null $expectedResponse, string $expectedEndpoint, array $expectedParams): MockObject&GuzzleClient { - $mockResponse = $this->getMockBuilder(ResponseInterface::class) - ->getMock(); + $mockResponse = $this->createMock(ResponseInterface::class); if ($expectedResponse) { if (is_string($expectedResponse)) { @@ -33,9 +31,7 @@ public function mockGuzzleRequest(string|StreamInterface|null $expectedResponse, } } - $mockGuzzle = $this->getMockBuilder(GuzzleClient::class) - ->onlyMethods(['request']) - ->getMock(); + $mockGuzzle = $this->createMock(GuzzleClient::class); $mockGuzzle->expects($this->once()) ->method('request') ->with('POST', $expectedEndpoint, $expectedParams) @@ -44,49 +40,6 @@ public function mockGuzzleRequest(string|StreamInterface|null $expectedResponse, return $mockGuzzle; } - public function mockChunkedUploadClient(string $content, int $chunkSize): MockObject&Client - { - $chunks = str_split($content, $chunkSize); - - $mockClient = $this->getMockBuilder(Client::class) - ->setConstructorArgs(['test_token']) - ->setMethodsExcept(['uploadChunked', 'upload']) - ->getMock(); - - $mockClient->expects($this->once()) - ->method('uploadSessionStart') - ->with(array_shift($chunks)) - ->willReturn(new UploadSessionCursor('mockedSessionId', $chunkSize)); - - $mockClient->expects($this->once()) - ->method('uploadSessionFinish') - ->with('', $this->anything(), 'Homework/math/answers.txt', 'add') - ->willReturn(['name' => 'answers.txt']); - - $remainingChunks = count($chunks); - $offset = $chunkSize; - - if ($remainingChunks) { - $withs = []; - $returns = []; - - foreach ($chunks as $chunk) { - $offset += $chunkSize; - $withs[] = [$chunk, $this->anything()]; - $returns[] = new UploadSessionCursor('mockedSessionId', $offset); - } - - $mockClient->expects($this->exactly($remainingChunks)) - ->method('uploadSessionAppend') - ->withConsecutive(...$withs) - ->willReturn(...$returns); - } - - \assert($mockClient instanceof Client); - - return $mockClient; - } - public function createStreamFromString(string $content): Stream { $resource = fopen('php://memory', 'r+');